[BUG] Agent-team teammate pane crashes with "<Box> can't be nested inside <Text>" when ※ recap renders inline markdown code spans

Status Fixed / completed
Maintainer reply ✓ Yes — wolffiex
Activity 14 comments · opened Apr 22, 2026 · closed Apr 23, 2026
💡 Likely answer: A maintainer (wolffiex, collaborator) responded on this thread — see the highlighted reply below.

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 -CC control 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

  1. Start a Claude Code session with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1.
  2. Call TeamCreate to create a team.
  3. 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.)
  4. 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.
  5. At that render, the crash fires. Pane shows Ink error-boundary fallback (which, with tmux alternate-screen off, also mis-paints and dumps bundled cli.js source into the pane).
  6. 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 function crash 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).

View original on GitHub ↗

14 Comments

phobologic · 4 months ago

Reproducing this on v2.1.117 with a different trigger surface — same stack, same createInstance at cli.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 message field contained file paths or identifiers wrapped in backticks. Example from one of the dead sessions (last assistant turn before death):

SendMessage({
  to: "team-lead",
  summary: "STATUS pbp-8frp: read ticket, starting implementation",
  message: "STATUS dag-impl-2: read pbp-8frp, reviewed `post_loop.md`
            (658 lines). Ticket asks to extend the playwright-play skill
            prompt with: (1) a Pending Directives queue in `memory.md` ..."
})

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

  1. Teammate panes that crashed during a Read call, not a SendMessage. One of my implementers (dag-impl-2-3) died mid-Read of 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.
  1. Minified source dump amplifier is present without alternate-screen off. The reporter notes the ~2000-line cli.js dump only fires when tmux has set-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 v2.1.117 (Bun bundle)
  • macOS (Darwin 25.3.0), iTerm2, no tmux
  • CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
  • Models: Sonnet 4.6 (implementers/QRs), Opus 4.7 (team-lead)
  • 8 teammate panes spawned total, 5 crashed
ErikHodges · 4 months ago

Worked around by rolling back to last stable release 1.1.104 and confirmed the bug no longer occurs.

phobologic · 4 months ago

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/:

ls ~/.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 install subcommand (see claude install --help) that accepts stable, latest, or a specific version string:

claude install 2.1.114         # try a specific version
claude install stable          # or fall back to whatever the stable channel is on
claude --version               # verify what you ended up with

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_AUTOUPDATER to the env block of ~/.claude/settings.json:

{
  "env": {
    "DISABLE_AUTOUPDATER": "1"
  }
}

Merge that into your existing env block; don't replace other keys you have.

3. Repoint the launcher symlink to 2.1.114

ln -sfn ~/.local/share/claude/versions/2.1.114 ~/.local/bin/claude

(-sfn replaces the existing symlink in place rather than creating a nested symlink.)

4. Verify on next launch

Relaunch Claude Code, then:

claude --version       # should show 2.1.114
claude doctor          # should report the auto-updater as disabled

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, run claude update manually, and you're back on current.

---

Notes:

  • Don't delete the 2.1.117 directory under versions/ — keep it around so you can jump forward again easily once the fix is out.
wolffiex collaborator · 4 months ago

I'm having trouble reproducing this issue. If anyone can do /feedback and share the ID with me, I'll track it down

szwang · 4 months ago

Also, does turning off recap in /config (with the latest version) fix this?

vishnutskumar · 4 months ago

Additional datapoint — Linux, pre-content

Same error on 2.1.117 on Linux (no tmux, kitty terminal).

Invocation

env CLAUDECODE=1 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 claude \
  --agent-id <id>@<team> \
  --agent-name <name> \
  --team-name <team> \
  --agent-color green \
  --parent-session-id <uuid> \
  --agent-type general-purpose \
  --model claude-opus-4-7

Observation

The ERROR <Box> can't be nested inside <Text> component line 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

  • --print mode 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.
  • Platform is Linux x86-64 (bun-packed ELF, kitty, no tmux) — so the crash class isn't tmux- or macOS-specific.

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.

ivan01march · 4 months ago

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>.

vzakharov · 4 months ago

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:

- createInstance  /$bunfs/root/src/entrypoints/cli.js:496:249
- jS                                      cli.js:478:57937
- E$H                                     cli.js:478:87797
- WRH                                     cli.js:478:87009
- nFH                                     cli.js:478:85908
- lFH                                     cli.js:478:85729
- Rp                                      cli.js:478:82464
- tH                                      cli.js:478:6491
- NH                                      cli.js:478:4977
- oH                                      cli.js:478:5279

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.

KathrynN · 4 months ago

Happening in ghostty with tmux too - seems to crash almost immediately. Reverting claude to 2.1.114 did indeed resolve the issue.

mhegazy contributor · 4 months ago

Thanks for reporting. fix should be in tommorow's release.

phobologic · 4 months ago

@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.

phobologic · 4 months ago

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.

mhegazy contributor · 4 months ago

the fix should be in v2.1.120, if you are still seeing the issue please reopen.

github-actions[bot] · 3 months ago

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.