Skip to content

Fix Timebox depth leak on array/object constructors #120 - #121

Open
lawrencej004 wants to merge 2 commits into
dashjoin:mainfrom
lawrencej004:fix/timebox-depth-leak-120
Open

lawrencej004 wants to merge 2 commits into
dashjoin:mainfrom
lawrencej004:fix/timebox-depth-leak-120

Conversation

@lawrencej004

@lawrencej004 lawrencej004 commented Oct 6, 2026 •

Copy link
Copy Markdown

Fixes #120

Problem

With Frame.setRuntimeBounds(timeout, maxDepth) set, evaluating an array constructor with 2+ items, or an object constructor with 2+ keys, inside a loop fails with Stack overflow error ... Depth=N+1 max=N once the loop runs more than maxDepth times, even though nothing recurses.

The array constructor and evaluateGroupExpression set isParallelCall = idx > 0 on the environment for each item but never reset it. When evaluate then fires the exit callback for the constructor itself, the flag is still true, so Timebox skips the decrement for an entry it counted. Depth grows by one each time the constructor is evaluated.

Fix

Save isParallelCall before each loop and restore it afterwards. It's restored to the previous value rather than set to false, so a constructor nested as a non-first item of another constructor (e.g. [$i, [$i, $i]]) still has its skipped entry matched by a skipped exit.

Tests

New tests in RuntimeTest, all with maxDepth=10 and a 30-iteration $map:

  • testRuntimeBoundsArrayConstructorInLoop: [$i, $i]
  • testRuntimeBoundsNestedArrayConstructorInLoop: [$i, [$i, $i], $i]
  • testRuntimeBoundsObjectConstructorInLoop: {'a': $i, 'b': $i}
  • testRuntimeBoundsRecursionWithArrayConstructor: real recursion through an array constructor still throws
  • testRuntimeBoundsDepthBalancedAfterConstructors: Timebox depth is back to 0 after a loop over nested array/object constructors. This fails if the flag is reset to false instead of restored (depth goes to -90), not just on main

The loop tests fail on main with Depth=11 max=10 and pass with the fix. The full suite, including the generated JSONata test suite, passes locally: 1772 tests, 0 failures, 3 skipped.

🤖 Generated with Claude Code

The array constructor and evaluateGroupExpression set
environment.isParallelCall for every item after the first but never
reset it, so the exit callback for the constructor itself was skipped
and Timebox depth grew by one per evaluation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@lawrencej004
lawrencej004 marked this pull request as ready for review October 6, 2026 10:50
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Timebox depth leaks on array/object constructors, causing false "Stack overflow error" with setRuntimeBounds

1 participant