Skip to content

fix: self-referential thunks produce clean error instead of StackOverflowError - #1020

Merged
stephenamar-db merged 1 commit into
databricks:masterfrom
He-Pin:fix/self-referential-thunk
Jun 24, 2026
Merged

stephenamar-db merged 1 commit into
databricks:masterfrom
He-Pin:fix/self-referential-thunk

Conversation

@He-Pin

@He-Pin He-Pin commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor

fix: self-referential thunks produce clean error instead of StackOverflowError

Motivation

local x = x; x (self-referential thunk) caused an uncontrolled java.lang.StackOverflowError with raw Java stack trace. C++ jsonnet, go-jsonnet, and jrsonnet all produce clean, controlled error messages.

Modification

  • Val.scala: Added evaluating: Boolean flag to LazyExpr. Set to true on first evaluation; if the same LazyExpr is re-entered during evaluation, cycle is detected and "Infinite recursion detected (self-referential thunk)" is thrown.
  • Approach matches jrsonnet's Pending state sentinel.
  • Added error test: error.self_referential_thunk.jsonnet

Result

Expression cpp-jsonnet go-jsonnet jrsonnet sjsonnet (before) sjsonnet (after)
local x = x; x "max stack frames" "max stack frames" "infinite recursion" StackOverflowError 💥 "Infinite recursion detected" ✅
local f() = f(); f() "max stack frames" "max stack frames" "stack overflow" "Max stack frames" ✅ "Max stack frames" ✅
local x = 1+2; x 3 3 3 3 ✅ 3 ✅

…flowError

Motivation:
`local x = x; x` caused an uncontrolled java.lang.StackOverflowError
with a raw Java stack trace. C++ jsonnet, go-jsonnet, and jrsonnet
all produce clean, controlled error messages for self-referential
thunks.

Modification:
- Val.scala: Add `evaluating` boolean flag to LazyExpr. When value
  is first requested, set the flag to true. If value is requested
  again while the flag is true, it's a cycle — throw a clean error:
  "Infinite recursion detected (self-referential thunk)".

Result:
Self-referential thunks now produce a clean sjsonnet.Error instead
of crashing the JVM.

Cross-implementation comparison:
| Expression | cpp-jsonnet | go-jsonnet | jrsonnet | sjsonnet (before) | sjsonnet (after) |
|---|---|---|---|---|---|
| local x = x; x | "max stack frames" | "max stack frames" | "infinite recursion" | StackOverflowError 💥 | "Infinite recursion detected" ✅ |
| local f() = f(); f() | "max stack frames" | "max stack frames" | "stack overflow" | "Max stack frames" ✅ | "Max stack frames" ✅ |
| local x = 1+2; x | 3 | 3 | 3 | 3 ✅ | 3 ✅ |
@stephenamar-db
stephenamar-db merged commit 5acc34e into databricks:master Jun 24, 2026
5 checks passed
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.

2 participants