Stop hook error: JSON validation failed masks real evaluator error on long /goal sessions
Summary
Bug: when a /goal condition's evaluator call fails, the CLI shows only "Stop hook error: JSON
validation failed", naming no hook and no real cause, even though the bundled changelog
describes this exact confusion as fixed about 165 releases earlier.
Expected behavior
The actual failure ("Hook evaluator API error: ...") should be shown, matching what the
changelog already describes as fixed.
Actual behavior
On a large session (roughly 59 MB, about 29,600 transcript lines) with an active /goal, the
turn ended with Stop hook error: JSON validation failed and no further detail, naming no hook.
The binary's own string table shows two adjacent, distinct messages in the same evaluator failure
path: Hook evaluator API error: (the accurate one) and JSON validation failed (the one
actually shown). An evaluator that fails this way returns no verdict, so the /goal condition
can be judged neither met nor impossible, and re-fires on every subsequent turn until cleared by
hand.
Minimal reproduction
Not reliably reproducible on demand; the failing step is a model call made inside the evaluator
and cannot be driven directly. Reliably observed with: an active /goal condition, itself fairly
long, in a session whose transcript has grown to tens of megabytes.
Environment
- Product and version: Claude Code CLI 2.1.263.
- OS and version: Linux (remote host).
- Model / resolved model ID: not directly implicated; failure occurs in the evaluator's own call.
- Runtime context: SSH-attached remote host, tmux-hosted session, roughly 59 MB / 29,600-line
transcript.
- Authentication/provider path: not relevant to the failure mechanism.
Diagnostics
The bundled changelog contains, at two release entries roughly 165 versions before the installed
build: "Fixed prompt-type Stop/SubagentStop hooks failing on long sessions, and hook evaluator
API errors displaying 'JSON validation failed' instead of the actual message." The installed
build's string table still contains both the generic and the specific message in the same code
path, with only the generic one surfaced to the user.
Regression and controls
- Fresh process/session: not independently retested on a fresh session; observed once, on the
transcript described above.
- Last known good version: unclear; the changelog implies a fix at 2.1.97/2.1.98, but the
confusion still occurs at 2.1.263.
- Relevant control: every locally-registered hook was independently tested against a realistic
Stop payload and each exited cleanly with no output, ruling out a locally-owned hook as the
cause.
Hypothesis
The fix referenced in the changelog either regressed or covers only part of the evaluator's
failure paths; a long transcript and a long condition text both feed into the same
evaluator prompt, and at least one remaining failure path there still surfaces the generic
message instead of the real one.
Related public reports
- #62246, #58712, #58558, #41393 (all closed) — earlier reports of the exact same displayed
message ("JSON validation failed") from the /goal Stop hook, each under a different specific
trigger (markdown to stdout, an @file reference, markdown-fenced JSON response, and a general
report that prompt-type Stop hooks always failed this way). All are closed, consistent with the
changelog's claimed fix, which makes the confusion's return in a much newer build worth
reporting on its own rather than reopening any of them.
- #58970, #60966 (both closed) — closed reports of the evaluator's "Prompt is too long" failure
specifically on long sessions, the same underlying trigger class named in the changelog entry
this report cites.
This report is a distinct, newer occurrence of the same displayed-message confusion, not a
duplicate of any of the above.