[BUG] Agent-team teammate pane crashes with "<Box> can't be nested inside <Text>" when ※ recap renders inline markdown code spans
Title: [BUG] Agent-team teammate pane crashes with "<Box> can't be nested inside <Text>" when ※ recap renders inline markdown code spans
Summary
In Claude Code v2.1.117 agent-teams mode, if a teammate's reply to team-lead contains inline markdown code spans (backtick-delimited text like ` uv run python ), the teammate's own pane crashes when Claude Code renders the ※ recap: compact-summary line. The Ink reconciler throws Error: <Box> can't be nested inside <Text> component from createInstance at cli.js:495:249. The crashed pane subsequently causes the whole team directory (~/.claude/teams/{name}/`) to be torn down, cascading to all other teammates.
This is distinct from #49865 (different error, different line, different trigger — and #49865 is fixed as of v2.1.114).
Environment
- Claude Code: v2.1.117 (confirmed), v2.1.116 (strongly suspected based on retrospective matching against prior session stalls, not re-tested)
- Platform: macOS (Darwin 24.5.0)
- Terminal: iTerm2 inside tmux (
tmux -CCcontrol mode) - Model: Sonnet 4.6 / Opus 4.7 (both observed)
- Feature flag:
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
Error (verbatim, from crashed pane)
Error: <Box> can't be nested inside <Text> component
at createInstance /$bunfs/root/src/entrypoints/cli.js:495:249
at BU cli.js:477:57938
at gTH / XWH / bgH / Ir / MWH / T_ / hH / eH
(React Fiber reconciler + Ink host config work loop)
The throw site in the bundled source:
createInstance(H, _, q, K, O) {
if (K.isInsideText && H === "ink-box")
throw Error("<Box> can't be nested inside <Text> component");
Combined with the host-context tracker a few lines earlier:
getChildHostContext(H, _) {
let q = H.isInsideText,
K = _ === "ink-text" || _ === "ink-virtual-text" || _ === "ink-link";
if (q === K) return H;
return { isInsideText: K };
}
This confirms an ink-box host element is being mounted while the parent context has isInsideText: true.
Reproduction
- Start a Claude Code session with
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. - Call
TeamCreateto create a team. - Spawn a teammate via
Agent(subagent_type=..., team_name=..., name=...)whose persona or spawn prompt encourages replies containing inline code formatting. (I reproduced with an agent whose spawn reply included the phrase `uv run python`, but any backtick-delimited inline code in the reply is sufficient.) - After the teammate sends its first reply to team-lead and goes idle, Claude Code renders the
※ recap:compact summary in the teammate's own pane. - At that render, the crash fires. Pane shows Ink error-boundary fallback (which, with tmux
alternate-screen off, also mis-paints and dumps bundledcli.jssource into the pane). - The whole team directory is torn down shortly after.
Expected: recap renders code spans inline, like the main message render does.
Actual: Ink reconciler throws from createInstance, pane enters zombie state, team is torn down.
Root-cause hypothesis
The ※ recap: component structure appears to be:
<Text>
※ recap: <InlineMarkdown content={previewText}/>
</Text>
Where InlineMarkdown emits a <Box> wrapper for code spans (for background-color / padding visual treatment):
<Box backgroundColor="gray" paddingX={1}>
<Text>uv run python</Text>
</Box>
The <Box> lands inside the outer <Text> wrapper → violates Ink's getChildHostContext invariant → throw.
Suggested fix
Two clean options:
Option A — change recap's outer wrapper from <Text> to <Box>, move prefix into inner <Text>:
// Buggy:
<Text>
※ recap: <InlineMarkdown content={preview}/>
</Text>
// Fixed:
<Box>
<Text>※ recap: </Text>
<InlineMarkdown content={preview}/>
</Box>
Option B — change the inline-code-span renderer to use <Text>-level styling instead of <Box> wrapping:
// Buggy:
<Box backgroundColor="gray" paddingX={1}><Text>{code}</Text></Box>
// Fixed:
<Text backgroundColor="gray"> {code} </Text>
Option B is probably more robust because it fixes the code-span component regardless of where it's used.
Evidence the bug is specific to recap rendering (not message receipt)
The main message render in team-lead's pane rendered the same backticked content correctly. Only the ※ recap: line in the teammate's own pane crashed. That points at a separate renderer path that wraps message content in a stricter container.
Selective-crash pattern across a 5-agent team
In one session, spawned 5 teammates. Only the two whose replies/received-content included backticks crashed:
| teammate | reply content | backticks? | outcome |
|---|---|---|---|
| planner | bare idle | no | clean |
| dev | bare idle | no | clean |
| qa | bare idle on spawn; later received brief with backticks from team-lead | no / yes (later) | clean on spawn, silent-stall later |
| researcher | bare idle | no | clean |
| tester | multi-line narrative with ` uv run python ` | yes | pane crash + source dump |
Also: crash fires mid-render of the ※ recap: line specifically — ✶ Doing… / ✢ Doing… status lines (which lack backticks) rendered cleanly before the crash.
Amplifier (orthogonal, self-fixed)
If the user's ~/.tmux.conf has set-option -g alternate-screen off, the Ink error-boundary fallback mis-paints and dumps ~2000 lines of bundled cli.js source into the pane (reproduced this myself). With tmux's default alternate-screen on, the fallback renders a clean error screen. This is user-side config and not Claude Code's responsibility, but worth noting for anyone reproducing.
Related issues
- #49865 —
getAppState is not a functioncrash on permission-prompt render. Different bug, fixed in v2.1.114. I initially wondered if they were related; they are not.
Workaround (current)
Include an explicit directive in teammate spawn prompts to ban backticks in SendMessage replies. Example: "NEVER use backticks, code fences, or inline code formatting in SendMessage content. Reference paths and identifiers as plain prose." This sidesteps the crash but is fragile (depends on agent compliance).
14 Comments
Reproducing this on v2.1.117 with a different trigger surface — same stack, same
createInstanceatcli.js:495:249, same<Box>/<Text>invariant. Adding data because the pattern here is broader than spawn-time replies.Scale
In a single DAG-orchestrated team run (1 team-lead + 4 implementers + 2 quality-reviewers + 1 AC-verifier), I had 5 separate teammate panes crash over ~30 minutes, across three different agent roles (implementer, QR, the team's respawn of each). The surviving agents were the ones whose SendMessage traffic happened not to contain backticks.
Trigger pattern matches yours exactly, but later in the conversation — not just spawn reply
Every death in my run happened shortly after the teammate sent a SendMessage to team-lead whose
messagefield contained file paths or identifiers wrapped in backticks. Example from one of the dead sessions (last assistant turn before death):Plain-prose STATUS messages from the same teammate role survived. The ones that name files in backticks died on the next render tick.
So the backtick trigger isn't limited to the initial teammate reply — any later SendMessage with inline code spans, if it ends up rendering into the
※ recap:line on the sender's own pane, crashes it. That makes the workaround ("ban backticks in spawn prompts") narrower than needed: the ban has to apply to the teammate's entire send history for the session, not just its first reply.Two orthogonal observations that may or may not be related
dag-impl-2-3) died mid-Readof a 1560-line test file, with no preceding backtick-containing SendMessage in the transcript. Possibly a different render path hitting the same invariant via tool-result preview rendering; possibly a different bug. Noting it in case it's useful signal — happy to open a separate issue if you want that split out.alternate-screen off. The reporter notes the ~2000-linecli.jsdump only fires when tmux hasset-option -g alternate-screen off. I reproduced the dump running Claude Code outside tmux entirely (bare iTerm2), so something else can trigger the mispaint too. Not the core bug, just a note on amplifier scope.Environment
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1Worked around by rolling back to last stable release 1.1.104 and confirmed the bug no longer occurs.
Yeah, I rolled back to 2.1.114 which was the last version I was using that didn't run into this. Here's some steps you can take to do the same.
Workaround: pin Claude Code to a pre-bug version
If #51855 is killing your agent-teams runs, you can roll back to
2.1.114(last version before the regression) and disable auto-updates so you stay there until the fix ships.1. Check what's available locally
Native installs keep previous versions around under
~/.local/share/claude/versions/:If you see
2.1.114(or another pre-2.1.116 version), skip ahead to step 2.If you don't have an older version cached, there's still a good chance you can grab one. The CLI ships with a
claude installsubcommand (seeclaude install --help) that acceptsstable,latest, or a specific version string:I haven't tested how far back arbitrary version strings resolve, so treat these as things to try rather than guaranteed to work. If you can't get to a pre-2.1.116 build either way, your best option is to wait for the upstream fix in #51855.
2. Disable the auto-updater
Per the official docs (https://code.claude.com/docs/en/setup#disable-auto-updates), add
DISABLE_AUTOUPDATERto theenvblock of~/.claude/settings.json:Merge that into your existing
envblock; don't replace other keys you have.3. Repoint the launcher symlink to 2.1.114
(
-sfnreplaces the existing symlink in place rather than creating a nested symlink.)4. Verify on next launch
Relaunch Claude Code, then:
5. Remember to undo this once the fix ships
When #51855 is closed and a new version is out, drop the env var from
settings.json, runclaude updatemanually, and you're back on current.---
Notes:
versions/— keep it around so you can jump forward again easily once the fix is out.I'm having trouble reproducing this issue. If anyone can do /feedback and share the ID with me, I'll track it down
Also, does turning off recap in
/config(with the latest version) fix this?Additional datapoint — Linux, pre-content
Same error on 2.1.117 on Linux (no tmux, kitty terminal).
Invocation
Observation
The
ERROR <Box> can't be nested inside <Text> componentline appears immediately after the spawn command in the parent's view, before any teammate-authored content has rendered — no ※ recap, no inbox \permission_request\/\permission_response\JSON, no MCP tool output. That is, earlier in the teammate lifecycle than the triggers in this issue, #52098, and #52139.Narrowing
--printmode on 2.1.117 with the same flags succeeds (the teammate self-introduces and exits cleanly), so the offending render lives on the interactive TUI spawn path specifically.Posting in case a pre-content render path is a cleaner localization target than the post-spawn content triggers already reported — if the offending
<Box>-in-<Text>is in the team banner / teammate chrome (color chip, identity tag, model badge), it would render unconditionally at spawn and would also explain why content-triggered variants compose cleanly on top of it.Reproduced on WSL2 Ubuntu 22.04 inside tmux, with both Claude Code v2.1.117 and v2.1.118.
Trigger: teammate (spawned via TeamCreate / Agent with team_name) sends a permission_request to the team lead. On the teammate pane the Ink reconciler throws <Box> can't be nested inside <Text>.
Reproducing on v2.1.118 on macOS (Darwin 24.5.0), iTerm2,
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1.Stack frames shifted slightly vs. the OP (v2.1.117) but the same path:
Trigger matches the OP exactly: the teammate crash fires on the
※ recap:render after the pane has been running a while. Every subagent in today's only team session ended up crashing.Happening in ghostty with tmux too - seems to crash almost immediately. Reverting claude to 2.1.114 did indeed resolve the issue.
Thanks for reporting. fix should be in tommorow's release.
@mhegazy Was this supposed to be fixed in v2.1.119? I noticed it came out last night a few hours after your message, but before midnight - and I'm still hitting the error while using that version.
Yeah, still breaking in 2.1.119. I saw 2.1.120 seemed to get released, then removed. So this is still broken at this point, though it seems liek there are new tickets for the same issue.
the fix should be in v2.1.120, if you are still seeing the issue please reopen.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.