Skip to content

Commit 10e443f

Browse files
committed
fix: make Frame.lookup() iterative to prevent StackOverflowError
Java does not optimize tail calls. On JVMs with smaller default thread stack sizes (e.g. Windows workers, containers with -Xss256k), deeply nested JSONata expressions cause Jsonata$Frame.lookup() to overflow the stack via tail recursion. StackOverflowError is a JVM Error — it cannot be safely caught and the entire worker thread crashes. Replace the recursive parent.lookup(name) call with an iterative loop over the scope chain. Semantics are identical; traversal order is unchanged. Eliminates all stack risk from scope chain lookup regardless of nesting depth. Fixes worker crashes reported in kestra-io/plugin-transform#79.
1 parent 0b40af3 commit 10e443f

1 file changed

Lines changed: 5 additions & 6 deletions

File tree

src/main/java/com/dashjoin/jsonata/Jsonata.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,11 @@ public void bind(String name, JFunction function) {
8989
public<A,B,R> void bind(String name, Fn2<A,B,R> lambda) { bind(name, (Object)lambda); }
9090

9191
public Object lookup(String name) {
92-
// Important: if we have a null value,
93-
// return it
94-
if (bindings.containsKey(name))
95-
return bindings.get(name);
96-
if (parent!=null)
97-
return parent.lookup(name);
92+
// Iterative walk of the parent scope chain to avoid StackOverflowError
93+
// on JVMs with small thread stacks (e.g. Windows workers).
94+
for (Frame f = this; f != null; f = f.parent) {
95+
if (f.bindings.containsKey(name)) return f.bindings.get(name);
96+
}
9897
return null;
9998
}
10099

0 commit comments

Comments
 (0)