Skip to content

[Bug]: raise <host exception object> loses the source location of the raise statement in the guest stack trace #1081

Description

@ftreede

Describe the bug

When Python code raises a pre-existing host (Java) exception object with a bare raise statement (e.g. raise IllegalArgumentException("..."), where IllegalArgumentException was exposed to Python via Context.getBindings("python").putMember(...)), the resulting PolyglotException's stack trace shows Unknown for the location of the frame that executed the raise. The location of the caller frame(s) further up the stack is still correct.

By contrast:

  • Raising a native Python exception (raise RuntimeError("...")) correctly records the source location of the raise statement.
  • A host exception thrown naturally from a real Java method (not via Python raise) also correctly records the Python call-site location of the invocation that triggered it.

So specifically it's the combination of "Python raise statement" + "operand is already a host exception instance" that loses its own location, while everything else around it is fine.

Operating system

Windows

CPU architecture

x86_64

GraalPy version

25.1.3

JDK version

No response

Context configuration

No response

Steps to reproduce

Minimal java example code:

try (Context context = Context.newBuilder("python")
        .allowAllAccess(true)
        .build()) {

    context.getBindings("python").putMember("IllegalArgumentException", IllegalArgumentException.class);

    context.eval(Source.newBuilder("python", """
            class Pure:
                def pyErr(self):
                    raise RuntimeError("Test Error")
                def javaErrInPy(self):
                    raise IllegalArgumentException("Test Error")
                def javaErrInPy2(self):
                    self.javaErrInPy()
            """, "test.py").buildLiteral());

    Value inst = context.getBindings("python").getMember("Pure").newInstance();

    try {
        inst.invokeMember("pyErr");
    } catch (PolyglotException e) {
        e.printStackTrace(System.out);
    }
    try {
        inst.invokeMember("javaErrInPy");
    } catch (PolyglotException e) {
        e.printStackTrace(System.out);
    }
    try {
        inst.invokeMember("javaErrInPy2");
    } catch (PolyglotException e) {
        e.printStackTrace(System.out);
    }
}

Actual output:

RuntimeError: RuntimeError: Test Error
    at <python> pyErr(test.py:3:65-96)
    ...

java.lang.IllegalArgumentException: Test Error
    at <python> javaErrInPy(Unknown)
    ...
Caused by host exception: java.lang.IllegalArgumentException: Test Error

java.lang.IllegalArgumentException: Test Error
    at <python> javaErrInPy(Unknown)
    at <python> javaErrInPy2(test.py:8:186-203)
    ...
Caused by host exception: java.lang.IllegalArgumentException: Test Error

Note javaErrInPy(Unknown) in both the second and third case, even though javaErrInPy2's call site is correctly resolved to test.py:8:....

Expected behavior

The javaErrInPy frame should carry the location of its raise IllegalArgumentException("Test Error") statement, analogous to the pyErr case, e.g. javaErrInPy(test.py:5:...).

Stack trace

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions