Subagent crash in cli.js:502 Ink error renderer (Bun)
Summary
A subagent process running under the experimental agent-teams flag crashes inside what appears to be the Ink UI error renderer at cli.js:502 — the renderer itself throws while attempting to render some other transient error, taking the whole process down silently. The result is a zombie process state where claude.exe is still tracked as alive in the harness registry but the application has actually exited.
Reproduction
Not deterministic; observed once during ~2 hours of agent-team work. Conditions present at the time:
- Subagent (
claude.exe --agent-id ... --agent-name ... --team-name ... --parent-session-id ...) running inside a tmux pane on aclaude-swarm-<pid>socket, ~18 minutes into its task. - The subagent had completed several
Readcalls and was mid-Readof another file when the crash hit. - A custom PreToolUse hook (
enforce-delegation.sh) had returned non-zero with empty stderr earlier in the session for an unrelated tool call. The model treated it as a tool error. The crash happened ~minutes later, not on that exact failure. - No other unusual condition observed; orchestrator was responsive throughout.
Observed behavior
Stack frames captured from the crash (function names match minified Bun bundle, cli.js:484:*):
Jo6({error: H}) { let _ = H.stack ? H.stack.split(...) ... }
at createInstance
at PL
at LYH
at rZH
at RD6
at iZH
at jM_
at aH
at LH
at FH
(all frames in cli.js:484:*)
The function Jo6({error:H}) is itself the error renderer — splitting H.stack to format it for display. The inner throw inside Jo6 is what kills the process; the outer error (the original H) is never surfaced.
After the crash:
- Subagent claude.exe terminates. tmux pane drops back to the parent shell prompt.
- No error message printed to the user. No
~/.claude/logs/entry. - The subagent's
config.jsonentry still hasisActive: trueand atmuxPaneIdthat maps to the now-empty pane. - A custom diagnostic (
swarm-doctor) detects this only via the contradiction between (isActive=truein registry) and (pgrep --agent-name Xreturns nothing). - Re-spawning an identical subagent on the same task completes successfully, suggesting the trigger condition is transient (possibly a specific UI state during streaming).
Repro hypothesis
The Ink UI tries to render a transient error (perhaps a non-fatal stream interruption). The render path constructs a stack-trace display via Jo6. Jo6 accesses H.stack, splits it, expects something it doesn't get (undefined? empty string? recursive object?), and throws. There is no try/catch around the renderer, so the throw propagates to the Bun runtime and exits the process. The harness has no visibility into this — claude.exe just disappears.
Expected behavior
- The Ink error renderer must not crash while rendering an error. Wrap the renderer in a try/catch that falls back to plain stderr if rich rendering fails. The original error is far more important than the pretty formatting.
- Subagent crashes should produce a structured artifact the orchestrator can detect — e.g.
~/.claude/crashes/<session-id>-<agent-id>.jsoncontaining the stack trace, last tool call, last message, and timestamp. Today, the orchestrator has zero visibility into the crash; it only knows the agent is gone via process-table polling. - The runtime should never terminate silently. At minimum write the trace to
~/.claude/logs/crash-<ts>.log.
Why this matters for agent teams
With CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1, a subagent crash silently loses N minutes of context plus any in-flight tool work. The orchestrator must re-spawn from scratch (re-load knowledge files, re-derive state). There is no automatic recovery because the crash is invisible until process-table polling notices, which can be minutes later if the orchestrator is busy with another teammate. In our setup, this happened once in a ~2-hour session; with multi-agent teams running for longer, the impact compounds.
Environment
OS: macOS 24.6.0 (Darwin Kernel) ARM64 (Apple Silicon)
claude: 2.1.119 (Claude Code)
node: v22.16.0 (via nvm)
bun: 1.3.5 (Claude Code embeds the Bun runtime)
Terminal: Warp
Flag: CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
Role: subagent (claude.exe spawned via Agent() tool)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗