Skip to content

Exception stack trace truncated — cause chain not fully reported #118

@andrus

Description

@andrus

Summary

Generated by Claude

When an exception propagates out of a cell, JJava truncates the cause chain. Only the top-level wrapper exception and one level of Caused by (a jdk.jshell.EvalException) are shown. Any deeper causes — including the true root cause — are silently dropped, making it very hard to diagnose errors.

Steps to Reproduce

Run any code that throws an exception with a multi-level cause chain. A typical scenario is calling a method that catches a low-level exception (e.g. a NullPointerException inside a third-party library), wraps it in a domain exception, and throws that — producing a chain of two or more Caused by levels.

Actual Behavior

JJava prints only two levels of the exception chain:

java.lang.RuntimeException: com.example.MyServiceException, Operation failed
|       at org.dflib.jjava.kernel.execution.CodeEvaluator.evalSingle(CodeEvaluator.java:145)
|       at org.dflib.jjava.kernel.execution.CodeEvaluator.eval(CodeEvaluator.java:79)
|       at org.dflib.jjava.kernel.JavaKernel.doEval(JavaKernel.java:230)
|       ...
|   Caused by: jdk.jshell.EvalException: Operation failed
|       at com.example.client.MyClient.performAction(MyClient.java:116)
|       at com.example.client.MyClient.execute(MyClient.java:46)
|       at .(<Anonymous>#61:1)

The exception chain ends here. The two deeper Caused by frames — the intermediate library error and the root-cause NullPointerException — are missing entirely.

Expected Behavior

The full exception chain should be reported, matching what the JVM itself produces:

com.example.MyServiceException: Operation failed
    at com.example.client.MyClient.performAction(MyClient.java:116)
    at com.example.client.MyClient.execute(MyClient.java:46)
    ...
Caused by: Cannot invoke "String.length()" because "this.input" is null
    at com.thirdparty.lib.SomeClient.doRequest(SomeClient.java:161)
    at com.example.client.MyClient.performAction(MyClient.java:114)
    ... 9 more
Caused by: java.lang.NullPointerException: Cannot invoke "String.length()" because "this.input" is null
    at java.base/java.net.URI$Parser.parse(URI.java:3194)
    at java.base/java.net.URI.<init>(URI.java:649)
    ...

Root Cause (hypothesis)

CodeEvaluator catches the jdk.jshell.EvalException thrown by JShell and re-wraps it in a plain RuntimeException. In doing so, it likely reconstructs only one level of cause rather than recursively walking EvalException.getCause() to rebuild the full chain.

The relevant location appears to be CodeEvaluator.evalSingle() (line 145).

Impact

Without the root cause, debugging exceptions that originate inside third-party libraries is practically impossible from inside the notebook. The user is forced to reproduce the error outside of Jupyter to get a useful stack trace.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions