[BUG] [AGENT_TEAMS] Parallel Agent dispatch: 90min stall silently burns ~15M cache_read tokens, resets subagent context

Resolved 💬 5 comments Opened Apr 9, 2026 by scottmeyer Closed Jun 1, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Under CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1, a parallel Agent tool dispatch produced a long silent stall with three observable problems. All three were triggered by one assistant turn that emitted three parallel Agent tool_uses where at least one subagent ran a cargo test command that hit the Bash tool's 600 s auto-background timeout.

1. Notification queue stalled for 1 h 39 m 38 s. Two Async agent launched successfully tool_results were held in the harness notification queue and not delivered to the main agent's next inference round. During this window the main session performed zero inference work and burned zero tokens (verified by summing usage.* fields across all main-session assistant rows in the gap). The TUI spinner continued to tick as Prestidigitating… 1h 39m 52s · ↓ 53.2k tokens — but the 53.2k number does not correspond to any measured activity in the JSONL (main burn was 0, subagent burn was ~15 M; the spinner figure matches neither).

2. Subagents reset silently on queue pump. When the queue finally drained at 21:03:09Z, both stalled subagents had their context erased and were reset to their original dispatch prompt. Their JSONL files contain a row with parentUuid: null and the original 19:23/19:24 dispatch timestamp re-injected, followed by a fresh assistant turn at 21:03:11Z with cache_read_input_tokens: 0. Approximately 290 rows of completed work per subagent disappeared from their context. No type: system event, no compact_boundary, no notification marks this reset in either the subagent JSONL or the main-session JSONL.

3. ~$22.50 silent cache_read overage. While the main session was stalled, the two blocked subagents were polling their own auto-backgrounded cargo test commands (each poll ~100-150 k cache_read tokens) and silently accumulated ~14.96 million cache_read tokens between them — approximately $22.50 in overage billing at Opus 4.6 cache_read rates. None of this usage was visible to the main agent or to the user during the stall. Scales linearly with stall duration.

Tension with documented behavior. The context-management-2025-06-27 beta docs state verbatim:

"Context editing is applied server-side before the prompt reaches Claude. Your client application maintains the full, unmodified conversation history. You do not need to sync your client state with the edited version."

But the rewound artifacts in this incident were exactly the client-state JSONL files at ~/.claude/projects/.../subagents/agent-{id}.jsonl. Either the harness is applying server-side edits to client storage (contrary to docs), or a separate undocumented client-side clearing mechanism exists. We cannot distinguish between these interpretations from outside the harness.

The auto-update landed mid-dispatch. This is the most striking timing correlation in the incident and we want to flag it prominently, while being clear we are not claiming causation. v2.1.98 was released upstream at 19:18 UTC. The on-disk binary at ~/.local/share/claude/versions/2.1.98 has an mtime of 19:25:24 UTC — i.e. the auto-updater replaced the binary on disk 29 seconds after builder-3's Agent tool_use was emitted (19:24:55 UTC) and 7 m 34 s before the main session went silent (19:32:58 UTC). The disk replacement happened while the harness was still servicing the three-way parallel dispatch. The running Claude Code process continued executing v2.1.97 code because Claude Code does not hot-reload — every JSONL row still shows version: 2.1.97. macOS allows a running binary to be replaced atomically without breaking the running process, so the replacement by itself should not cause a stall; however, auto-updaters can interfere in subtler ways (sending signals, swapping sidecar files, restarting helper processes, competing for IPC sockets). We also note that the nine synchronized background-command kills at 20:38:27 UTC all reported exit code 144 (128 + 16 = SIGUSR1 on most Unix systems), which is a suggestive signal-handling correlation. Anthropic engineers with access to the auto-update code path can answer definitively whether the two events are related.

Version-reporting secondary observation: at the time of writing this report (while the same session is still alive), claude --version on disk reports 2.1.98. Long-lived Claude Code processes can therefore execute arbitrarily old code with no in-session indicator that the on-disk binary has moved ahead. For bug triage, the JSONL version field reflects the launch-time version, not the disk version at any given moment.

Changelog overlap. The v2.1.98 changelog contains the entry "Fixed background subagents that fail with an error not reporting partial progress to the parent agent", which sounds close but is not identical — our subagents did not fail with an error, they stalled in polling loops, and the broken notification was the launch-time ack itself, not partial progress. Whether v2.1.98+ fixes the specific notification-queue-starvation and silent-reset path described here is an open question; we can re-run the reproduction on a fresh session (which will pick up the current disk binary) and amend this report.

What Should Happen?

| Observed | Expected |
|---|---|
| Async agent launched successfully tool_result delivered 5978 s after the Agent tool_use | Launch acknowledgements should be delivered to the main agent's next inference round within milliseconds of dispatch |
| Main agent has no signal while stalled: no error, no timeout, no pending-call metadata, no heartbeat | Main agent should receive some signal when waiting on async tool_results — minimally a passive pending_agent_tool_uses: [id, …] metadata on each turn; ideally a timeout or heartbeat after a reasonable wait |
| Subagent context silently erased on queue pump (290+ rows removed per subagent, no marker) | Either (a) preserve subagent context across the stall, or (b) emit a type: system row with a clear subtype (e.g. subagent.context_reset) at the point of any reset so the event is visible in the JSONL |
| ~15 M subagent cache_read tokens burned invisibly during parent stall | Subagent token usage during parent-session stall should be bounded, surfaced to the main agent, or both |
| Spinner shows ↓ 53.2k tokens that doesn't correspond to any measured field in the JSONL | Spinner token number should correspond to a real usage field from the session (main burn, subagent burn, or a clearly-labeled sum) |
| User's "what are you doing??" input held in queue for 66 s | User input should pump the notification queue immediately, not sit behind other queued events |
| Nine background-command kills at the same millisecond window with exit code 144, no explanation delivered to the main agent | Harness-initiated kills should produce an observable row with the reason (watchdog, memory budget, wall-clock cap, etc.) |

Underlying principle: whatever happened at 21:03:11Z to the subagents should have been observable from the main session's JSONL, from the subagent's own JSONL, or from both. Silent client-state mutation without a type: system event is indistinguishable from data loss from an agent's perspective.

Error Messages/Logs

All paths are in the local `~/.claude/projects/-Users-/234a9143-9ffc-4d16-b49e-e9c4ad4837b8/` tree. Session ID: `234a9143-9ffc-4d16-b49e-e9c4ad4837b8`.

### 1. 90-minute zero-token gap in the main session


[1042] 2026-04-09T19:32:58.021Z user       :: tool_result[toolu_014MfTTL] "Release build is clean…"   ← builder-3 (sync) done
[1043] 2026-04-09T20:38:27.971Z queue-op   :: enqueue "Background command … failed with exit code 144"
 …  30 additional queue-ops, none dequeued during this window  …
[1075] 2026-04-09T21:03:19.079Z assistant  :: stop=end_turn  in=6  cc=77344  cr=0  out=990            ← first post-gap inference


Sum of `usage.{input_tokens, cache_creation_input_tokens, cache_read_input_tokens, output_tokens}` across all main-session assistant rows in the 19:32:58 → 21:03:19 window: **0 / 0 / 0 / 0**. Row 1075's `cache_read: 0` confirms the 5-minute ephemeral cache had expired during the idle.

### 2. Launch acknowledgements delivered 5978 seconds late


[1039] 2026-04-09T19:23:31.467Z assistant  :: tool_use Agent id=toolu_01XjSTKARo5tYJ7J7MBAkKpy  (builder-1)
[1040] 2026-04-09T19:24:09.738Z assistant  :: tool_use Agent id=toolu_0155mboa67moj7EGmRfxJHsE  (builder-2)
[1041] 2026-04-09T19:24:55.xxxZ assistant  :: tool_use Agent id=toolu_014MfTTL                  (builder-3, sync — returned inline at row 1042)
 …
[1057] 2026-04-09T21:03:09.164Z user       :: tool_result[toolu_01XjSTKARo5tYJ7J7MBAkKpy] "Async agent launched successfully. agentId: ac1bf7bd243fcbf5c …"
[1058] 2026-04-09T21:03:09.164Z user       :: tool_result[toolu_0155mboa67moj7EGmRfxJHsE] "Async agent launched successfully. agentId: aa44dd5aab6ff73f4 …"


- Builder-1 launch-ack delay: **5978 s (1 h 39 m 38 s)**
- Builder-2 launch-ack delay: **5940 s (1 h 39 m)**

### 3. Silent subagent context reset

File: `~/.claude/projects/-Users-/234a9143-9ffc-4d16-b49e-e9c4ad4837b8/subagents/agent-ac1bf7bd243fcbf5c.jsonl`


// row 294 — parentUuid null, original dispatch prompt re-injected with ORIGINAL timestamp
{"parentUuid": null,
 "isSidechain": true,
 "promptId": "39575f13-6445-4ded-af21-779e5b683fac",
 "agentId": "ac1bf7bd243fcbf5c",
 "type": "user",
 "message": {"role": "user",
             "content": "You are @builder-1 for Wave A of a 4-item shipping plan. …"},
 "uuid": "b9e2dad0-9d45-4976-bf1c-b7ea0e1ee153",
 "timestamp": "2026-04-09T19:23:31.468Z",           // ← original dispatch ts, not 21:03
 "version": "2.1.97"}

// row 295 — brand new assistant turn, cache_read=0, fresh requestId
{"timestamp": "2026-04-09T21:03:11.359Z",
 "message": {"usage": {"input_tokens": 6,
                       "cache_creation_input_tokens": 13809,
                       "cache_read_input_tokens": 0,
                       "output_tokens": 1},
             "content": [{"type": "text",
                          "text": "I'll start by loading the kernel and then reading the required context."}]}}


Same `agentId`, same `promptId`, same `slug` (`declarative-munching-allen`), same dispatch prompt. Approximately 290 rows of completed work (including tool_use + tool_result pairs that had already produced on-disk source-file edits) are no longer present in the subagent's context. Builder-2's row 295 is structurally identical.

Search results for system events in either subagent JSONL:
- `type: system` rows: **0**
- `compact_boundary` rows: **0**
- `subtype: *` rows: **0**
- notifications to main session about the reset: **0**

### 4. Subagent token burn during the stall

Sums of `usage.*` across all subagent assistant rows in the 19:32:58 → 21:03:19 window:

| Subagent | input | cache_create | cache_read | output | total |
|---|---:|---:|---:|---:|---:|
| builder-1 | 81 | 848 139 | 7 701 114 | 11 749 | **~8.56 M** |
| builder-2 | 56 | 1 205 112 | 5 182 015 | 12 369 | **~6.40 M** |
| **total** | | | | | **~14.96 M** |

At Opus 4.6 cache_read rate ($1.50 / MTok), the silent overage is **approximately $22.50**. Main session burn in the same window: **0**.

### 5. Bash 600 s auto-background cascade


builder-1 [192] 2026-04-09T19:33:07.787Z assistant TU:Bash(cargo test --test agent_coordination …)
builder-1 [193] 2026-04-09T19:43:07.802Z user      TR:Command running in background with ID: bs04retv8


Six separate 600.0-second gaps between Bash tool_use and the resulting `Command running in background with ID: …` tool_result across the two builders' first incarnations. Once auto-backgrounded, each subagent entered a `sleep N && cat output_file` polling loop that consumed ~100-150 k cache_read tokens per iteration.

### 6. Nine synchronized background-command kills with exit 144


[1043-1050] 2026-04-09T20:38:27.971-980Z queue-op :: enqueue
  "Background command 'Full cargo test' failed with exit code 144"
  × 9 entries, timestamps within a 9 ms window


Nine separate background commands killed at the same millisecond window — signature of a synchronized harness watchdog kill. Exit 144 = 128 + 16 = `SIGUSR1` on most Unix, but we cannot confirm whether this is a harness-custom signal or a global watchdog. None of these notifications were delivered to the main agent.

### 7. User input also queued


[1054] 2026-04-09T21:02:03.628Z queue-op :: enqueue "what are you doing??"      ← user input
[1057] 2026-04-09T21:03:09.164Z user     :: tool_result[…]                       ← queue finally pumps (66s later)


The user's keyboard input sat in the queue for 66 s before delivery. The queue drained at 21:03:09Z with 14 dequeue events in a 0.1 s window. The exact pump trigger is not visible in the JSONL.

### 8. Search for context-editing / auto-compact events

- Only `compact_boundary` row in the entire main session: row 996, `trigger=manual`, at 18:58:40 UTC — **24 minutes before** the incident. This is an unrelated manual compaction.
- `compact_boundary` rows in either subagent JSONL: **0**
- `type: system` rows in either subagent JSONL: **0**
- `service_tier` value on all 629 main-session assistant rows: **`standard`** (no tier escalation logged, despite a `Now using extra usage` banner displayed in the TUI)

Steps to Reproduce

Environment at time of incident:

| Field | Value |
|---|---|
| Claude Code version | 2.1.97 (the running process in which the incident was observed; verified via the version field on every JSONL row). The on-disk binary at ~/.local/share/claude/versions/2.1.98 has an mtime of 2026-04-09 19:25:24 UTC — i.e. the auto-updater replaced the binary 29 seconds after builder-3's Agent tool_use was emitted at 19:24:55 UTC, and 7 m 34 s before the main session went silent at 19:32:58 UTC. The running instance continued executing v2.1.97 because Claude Code processes do not hot-reload across binary updates. The JSONL version field is the launch-time version, not the disk version at time of row. See "What's Wrong?" for discussion of whether the auto-update-timing correlation is causal or coincidental. |
| Model | claude-opus-4-6 |
| Platform | Darwin 25.4.0 (Apple Silicon) |
| Login | Claude Max Account |
| Service tier | standard (all 629 main-session assistant rows) |
| Session ID | 234a9143-9ffc-4d16-b49e-e9c4ad4837b8 |
| Feature flag | CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 (in ~/.claude/settings.json env block) |
| skipDangerousModePermissionPrompt | true |
| effortLevel | high |

Required ingredients:

  1. CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 in ~/.claude/settings.json env block.
  2. One assistant turn emits 3+ parallel Agent tool_uses, where at least one returns synchronously (inline) and at least one returns asynchronously (Async agent launched successfully).
  3. An async subagent runs a command that exceeds the Bash tool's 600 000 ms hard timeout — e.g. cargo test on a large Rust project, pytest on a slow suite, a stuck integration test.
  4. The user does not type anything for >10 minutes. (Typing input eventually pumps the queue; without user input the queue appears to sit indefinitely.)

Suggested minimal reproduction in a Claude Code session with the flag set:

Prompt to Claude:

Dispatch three parallel Agent tool calls. Two of them should run
`sleep 1200 && echo done`. One should run `echo immediate`. After
dispatching, do not respond until all three return.

Then do not type anything. Watch the spinner tick past 20 minutes. Check the main session JSONL — expected count of new assistant inference rows during the wait: zero. Eventually type any input; observe that both launch-ack tool_results arrive together after a delay matching the wall-clock since dispatch, and observe whether either subagent's JSONL shows a parentUuid: null row with the original dispatch timestamp re-injected.

Observed in our incident (your mileage may vary on other repos / test suites / wall-clock conditions):

  • Stall duration: 1 h 39 m 38 s
  • Main-session tokens burned during stall: 0
  • Subagent cache_read tokens burned during stall: ~14.96 M (~$22.50)
  • Rows removed from each rewound subagent's context: ~290
  • System events marking the reset: 0

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.97

Claude Code Version

2.1.98

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

This report is a condensed version of a fuller forensic investigation. The longer report includes the hypothesized mechanism for how the notification queue, the subagent reset, and the context-editing beta may interact; a detailed discussion of the relationship to context-management-2025-06-27; the v2.1.98 release overlap; and prior-art links. It is available on request or can be pasted as a follow-up comment on this issue if helpful.

Files available on request (happy to share in full or redacted):

  • Main session JSONL (1159+ rows)
  • Three subagent JSONLs (two rewound, one clean)
  • ~/.claude/settings.json
  • Terminal screenshots of the Prestidigitating… 1h 39m 52s · ↓ 53.2k tokens spinner and the Now using extra usage banner

Related issues worth cross-referencing:

  • anthropics/claude-code#26215 — feature request for a CLI flag / settings.json option to control the context_management API parameter (not yet shipped; indicates user-facing control over the beta is not currently exposed)
  • sst/opencode#2871 — third-party discussion of context-management-2025-06-27 in the opencode project
  • Claude Code v2.1.98 release notes — released ~14 min before the incident; contains the entry "Fixed background subagents that fail with an error not reporting partial progress to the parent agent" which sounds close to our incident but appears to be scoped to a different case (see "What's Wrong?" above)

Willing to re-run the reproduction on v2.1.98 or the current latest version and amend this report with whether the stall and silent reset still occur. Please let us know if that would be useful.

Thank you to the Claude Code team for the work on agent teams and on the context-management beta. The v2.1.98 release is a clear signal that this surface area is being actively improved, and we want this specific notification-queue-starvation + silent-reset path to land on whichever internal ticket is tracking it so it doesn't get lost in the adjacent fixes.

View original on GitHub ↗

This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗