[BUG] Agent-teams teammate panes wedged with "<Box> can't be nested inside <Text>" Ink error on 2.1.119 — not reproducible on 2.1.138 (regression record + fix confirmation)
Bug report — formatted for anthropics/claude-code bug_report.yml
Source: BUG-REPORT.md (preserved). Reshaped after 2026-05-10 reverify on 2.1.138.
---
Title
[BUG] Agent-teams teammate panes wedged with "<Box> can't be nested inside <Text>" Ink error on 2.1.119 — not reproducible on 2.1.138 (regression record + fix confirmation)
Preflight Checklist
- [x] Searched existing issues — closest matches are #10313 (closed, different Ink CLI crash), #38941 (closed, Yoga/Ink renderer dump), #48670 (open, MCP needs-auth-cache misbehavior — overlaps with the trigger condition here).
- [x] Single bug report.
- [x] Latest version — verified on 2.1.138; original evidence on 2.1.119.
What's Wrong?
On Claude Code 2.1.119, agent-teams teammate panes spawned via TeamCreate + Agent({team_name}) deterministically crashed their Ink renderer with <Box> can't be nested inside <Text> component (thrown from cli.js:502:249) the first time a permission prompt rendered while the "N MCP server needs auth · /mcp" footer banner was active. The Claude process and tmux pane stayed alive (pgrep found the PID, tmux list-panes reported dead=0, team config still said isActive: true), but the teammate's message-consume loop wedged behind the dead renderer. The team lead saw indefinite silence — no error, no idle notification, no shutdown_response. Manual tmux kill-pane was the only recovery; TeamDelete then failed until the wedged member was manually removed from ~/.claude/teams/<team>/config.json.
On 2.1.138, the same trigger condition no longer reproduces (see "Additional Information"). I'm filing this anyway because:
- The 2.1.119 crash was severe (silent teammate wedge with no signal path) and worth a searchable record in case of regression.
- If the fix was intentional, confirming the responsible change/version helps users who hit this on older binaries triage their workaround.
- If the non-repro is accidental (e.g. the banner-rendering component got refactored, but the underlying invalid composition still exists in a less-exercised path), it's worth flagging.
What Should Happen?
(a) Teammate renders the permission prompt + footer banner without crashing. (b) Even if a render error occurred, it should propagate to the agent-teams supervisor as an agent_crashed event, not present as indefinite silence with isActive: true.
Error Messages/Logs
From the 2.1.119 wedged teammate pane:
ctx: 6 / 1000000 (2%)
1 MCP server needs auth · /mcp
ERROR <Box> can't be nested inside <Text>
component
/$bunfs/root/src/entrypoints/cli.js:502:249
Throwing site (Ink reconciler createInstance, minified from Bun bundle):
createInstance(H,_,q,K,O){
if(K.isInsideText && H==="ink-box")
throw Error("<Box> can't be nested inside <Text> component");
let T = H==="ink-text" && K.isInsideText ? "ink-virtual-text" : H;
let $ = Yq_(T);
...
}
Call stack tail:
- createInstance (/$bunfs/root/src/entrypoints/cli.js:502:249)
- PL (/$bunfs/root/src/entrypoints/cli.js:484:58456)
- LYH (/$bunfs/root/src/entrypoints/cli.js:484:88642)
- rZH (/$bunfs/root/src/entrypoints/cli.js:484:87842)
- RD6 (/$bunfs/root/src/entrypoints/cli.js:484:86738)
- iZH (/$bunfs/root/src/entrypoints/cli.js:484:86558)
- jM_ (/$bunfs/root/src/entrypoints/cli.js:484:83272)
- aH (/$bunfs/root/src/entrypoints/cli.js:484:6552)
- LH (/$bunfs/root/src/entrypoints/cli.js:484:5006)
- FH (/$bunfs/root/src/entrypoints/cli.js:484:5318)
Names minified (Bun bundle), but line/col offsets are stable for 2.1.119 and should source-map cleanly.
Steps to Reproduce
(Historical — on 2.1.119. Same steps on 2.1.138 do not reproduce; see "Additional Information".)
- Ensure at least one MCP server is in needs-auth state:
``bash``
cat ~/.claude/mcp-needs-auth-cache.json # must be non-empty
- From a Claude Code session, create a team and spawn one general-purpose teammate:
``ls /tmp/__nope__$$ 2>&1 || echo NOT_FOUND
TeamCreate({ team_name: "repro" })
Agent({
subagent_type: "general-purpose",
team_name: "repro",
name: "worker",
prompt: "Run via Bash and reply with the output."``
})
- Wait for the teammate to send a
permission_request, then grant it.
- Observed on 2.1.119: teammate pane crashes with the Box-in-Text error and freezes; no reply; subsequent SendMessages land in inbox JSON but
readstaysfalseforever. Reproduced 4× across two runs with two trigger tools (Bash + Write).
Claude Model
Opus (claude-opus-4-7). Healthy comparison teammate in the same 2.1.119 session used Haiku/Explore and never hit a permission prompt — model was not the variable; the permission-prompt + auth-banner composition was.
Is this a regression?
I don't know. The behavior was new-observation on 2.1.119; not bisected against older versions. (For 2.1.138 the bug appears resolved.)
Last Working Version
N/A — not bisected.
Claude Code Version
Evidence: 2.1.119. Reverify: 2.1.138 (cannot reproduce — see below).
Platform
Anthropic API.
Operating System
macOS (Darwin 25.3.0 / macOS 26.3.1 on the original 2.1.119 host; Darwin 25.4.0 / macOS 26.3.1 on the 2.1.138 reverify host).
Terminal/Shell
Original (2.1.119): iTerm2, agent-teams backend = tmux (socket claude-swarm-18922), teammateMode: "tmux".
Reverify (2.1.138): tested both iTerm2 host (iterm2 backend) and Ghostty host (tmux backend) — neither reproduces.
Additional Information
Reverify on 2.1.138 (2026-05-10)
Same trigger condition (10 MCP servers in ~/.claude/mcp-needs-auth-cache.json, including the same claude.ai connectors that triggered the original crash), same spawn pattern (TeamCreate + general-purpose Agent with team_name), same minimal prompts (single Bash perm prompt; multi-stage Bash + Write + Read perm prompts). Three runs:
| # | Host terminal | Backend (per team config) | Stages | Result |
|---|---|---|---|---|
| 1 | iTerm2 | iterm2 | Bash perm prompt | Worker replied cleanly in ~36s |
| 2 | iTerm2 | iterm2 | Bash + Write + Read perm prompts | All stages clean in ~24s |
| 3 | Ghostty | tmux | Bash + Write + Read perm prompts | All stages clean in ~20s |
Run 3 is the closest match to the 2.1.119 conditions (tmux backend, same trigger). It does not reproduce.
2.1.119 evidence (preserved)
MCP needs-auth state at teammate spawn (original):
$ cat ~/.claude/mcp-needs-auth-cache.json
{"claude.ai Gmail": {"timestamp":1777220169909},
"claude.ai Google Drive":{"timestamp":1777220169912},
"claude.ai Google Calendar":{"timestamp":1777220169922}}
All three timestamps = 2026-04-26 16:16:09 UTC, ~4 seconds before the wedged teammate spawned.
Round-by-round (2.1.119):
| Round | Spawn time | MCP needs-auth | Outcome |
|---|---|---|---|
| R1 (gp-alpha, gp-beta) | 16:11–16:13 | empty | All 5 stages passed |
| R2 (ex-gamma, gp-delta) | 16:16:13+ | 3 servers | gp-delta crashed on first permission-prompted Bash |
| R2 retry | 16:18+ | 3 servers | gp-delta crashed on first permission-prompted Write |
| Stage C | later | re-populated (had "disabled" via /mcp but it re-populated) | crashed identically |
Timeline from inbox JSON (R2):
16:16:50 ex-gamma → gp-delta [DM] work request
16:16:54 gp-delta → team-lead [permission_request] for Bash
16:17:03 team-lead → gp-delta [permission_response] granted
~16:17 CRASH (renderer throws). gp-delta sends nothing further.
16:18:38 team-lead → gp-delta [ping] — written, read:false
16:21:40 team-lead → gp-delta [shutdown_request] — written, read:false
Process state during the wedge:
$ pgrep -lf "agent-id gp-delta"
40165 /Users/sauravvarma/.local/share/claude/versions/2.1.119
--agent-id gp-delta@team-stress-test --agent-name gp-delta ...
$ tmux -L claude-swarm-18922 list-panes -a -F '#{pane_id} pid=#{pane_pid} dead=#{pane_dead}'
%2 pid=39574 dead=0 (gp-delta — wedged, but pane reports alive)
team-config.json continued to list gp-delta as isActive: true indefinitely.
Recovery on 2.1.119 (verified)
| Method | Result |
|---|---|
| SendMessage shutdown_request to wedged teammate | ❌ written to inbox, never marked read |
| SendMessage plain ping | ❌ same |
| Keyboard input on pane | ❌ no input box rendered |
| tmux kill-pane -t %N | ✅ kills pane + claude process |
| TeamDelete after kill-pane | ❌ fails: Cannot cleanup team with 1 active member(s). Workaround: manually remove the wedged member from ~/.claude/teams/<team>/config.json then TeamDelete succeeds. |
Suggested investigation areas
- Identify and confirm the change between 2.1.119 and 2.1.138 that resolved this — likely a fix in the component rendering the "N MCP server needs auth · /mcp" footer banner (composed
<Box>inside<Text>only when paired with a permission-prompt panel). - Independent of this specific crash, the agent-teams supervisor still has no path from "teammate Ink renderer dies" → "team lead sees agent_crashed event." Even if this exact composition is gone, the next render error in a teammate will present identically (silent wedge,
isActive: trueforever). Either catch render errors in the teammate process and emit an outboundagent_crashedSendMessage, or have the supervisor detect inbox writes accumulating with noread:trueupdates. TeamDeleteshould accept a force flag, or auto-clean when a member is unreachable.- Related:
mcp-needs-auth-cache.jsonrepopulating within minutes even after/mcpdisable (anddisabledMcpServersnot taking effect mid-session) — overlap with #48670.
Workaround for users still on 2.1.119 or earlier
Before any agent-teams session, ensure ~/.claude/mcp-needs-auth-cache.json is empty. If non-empty:
- Complete
/mcpauth for each listed server and then restart Claude Code (the disable does not take effect inside a running session), or - Add the listed server names to
projects[<your-cwd>].disabledMcpServersin~/.claude.jsonand restart.
Do not just delete the cache file — it re-populates within minutes.
Cross-references
- #10313 (closed) — earlier generic Ink CLI crash
- #38941 (closed) — Yoga/Ink renderer source dump on crash
- #48670 (open) — MCP needs-auth-cache blocks reconnection even after re-auth (same underlying cache-staleness that produces the persistent banner observed here)
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗