2.1.198: headless -p run exits ~50s after model launches Agent subagent with run_in_background=true; bg wait ceiling not applied (regression from 2.1.197)
Summary
In Claude Code 2.1.198, a headless run (claude -p style, driven by anthropics/claude-code-action@v1 via the Agent SDK) exits roughly 50 seconds after the model launches an Agent-tool subagent with run_in_background: true. The backgrounded subagent is abandoned mid-work, no result message is emitted on the stream, and the run produces no output. The documented background-subagent wait ceiling for print mode (CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS, default 10 minutes) does not kick in.
The same workflow on 2.1.197 (previous day, same prompt) completed normally. The failure is intermittent because it depends on a model choice: on 2.1.198, runs where the model launches subagents as blocking calls still succeed; runs where it picks run_in_background: true die.
Environment
- Claude Code 2.1.198 (installed by
anthropics/claude-code-action@v1, commit6c0083bb7289c31716797a039b6367b3079cc46e, which bumps CLI 2.1.197 -> 2.1.198 and Agent SDK 0.3.197 -> 0.3.198) - Vertex AI provider (
CLAUDE_CODE_USE_VERTEX=1), modelclaude-opus-4-7 - Linux CI runner (Ubuntu 24.04), non-interactive
- Prompt: a multi-agent PR review orchestrator that instructs the model to "launch 5 Task sub-agents in parallel", collect their JSON findings, then post a review
What happened (from the stream JSON in the CI log)
13:37:58- orchestrator calls theAgenttool with"run_in_background": truefor the first review subagent. Tool result comes back immediately:
"tool_use_result": {
"isAsync": true,
"status": "async_launched",
"agentId": "a2d3cf5fb9e237fa1",
"resolvedModel": "claude-opus-4-7",
"outputFile": "/tmp/claude-1001/.../tasks/a2d3cf5fb9e237fa1.output",
"canReadOutputFile": true
}
13:38:00-13:38:01- the backgrounded subagent starts working (task_started,task_progress, first Read tool call and itstool_resultappear on the stream).- The stream then truncates mid
tool_resultmessage. No further assistant turns, no"type": "result"message at all. 13:38:51- the action step completes with exit code 0 and the job moves on. Total elapsed since the async launch: ~53 seconds. None of the orchestrator's later phases ran and nothing was written or posted.
For comparison, a run minutes later on the same 2.1.198 install, where the model happened to launch its subagents as blocking calls (no async_launched anywhere in the stream), completed all phases and ended with a normal "subtype": "success" result message. The last 2.1.197 run the previous day also completed normally.
Expected
Per the headless docs, print mode should wait for background subagents up to CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS (default 10 minutes), and the orchestrator should be able to collect the subagent's result and continue. Instead the process exits within about a minute, silently, with exit code 0.
Impact
Any headless orchestration prompt that fans out subagents now fails nondeterministically, depending on whether the model elects to background them. Exit code 0 makes the failure silent in CI.
Workarounds we applied
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1in the action env, which removesrun_in_backgroundfrom the Agent tool.- A prompt instruction to never pass
run_in_background. - Known-good fallback: pinning the action to the last commit shipping 2.1.197 (
fad22eb3fa582b7357fc0ea48af6645851b884fd).
Happy to provide fuller (lightly redacted) stream logs from the failing run if useful.
3 Comments
Corroborating data from 2.1.198 on macOS (Darwin 25.6.0):
In a 16-child harness (
claude -p --output-format json, repo cwd,--session-idset, each child dispatching 5–6 parallel Task/Agent subagents), stdout emitted no result envelope in 13/13 dispatching runs — exit 0, stderr empty, transcript JSONL complete, file side-effects all landed. 0-dispatch children under the identical invocation emitted well-formed{"type":"result",...}envelopes every time.A minimal repro with one synchronous Task dispatch from an empty cwd did not reproduce (well-formed envelope,
num_turns=2), which is consistent with the async/background-dispatch trigger described here rather than a flat dispatched-vs-not correlation. Distinguishing datum from our side: our failing children dispatched multiple subagents in parallel; we did not confirm from transcripts whether the harness sessions' Agent calls carriedrun_in_background: true— if useful, we can check the recorded JSONLs and report back.Repro harness and per-run records available on request.
Additional data points from a different launch path — an SDK streaming-input session (not one-shot
-p), Claude Code 2.1.201, Linux/WSL2, first-party API (no Vertex):tool_resultreturns "Workflow launched in background" immediately). In my setup the driver session launches one Workflow run and waits for its completion notification.CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MSdefault of 10 min.CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=60000on the spawning process kills the same child at 62s (the same workflow completes normally when it fits under the ceiling). Raising the ceiling is the workaround I've wired in.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1norCLAUDE_CODE_ENABLE_TASKS=falseprevents the Workflow tool from backgrounding (both verified present in the child's/proc/<pid>/environ), so there is currently no opt-out back to blocking launches in headless.Related: #64627 reports the same silent kill (~13 min there) with no completion/death signal to the parent — that matches what I see: the parent only discovers the death by polling disk/process state; no
result/failure message is emitted for the abandoned child.A headless opt-out (Workflow/Agent tool runs blocking again), or at minimum a death signal on ceiling expiry, would make orchestrating long multi-agent workflows via the SDK reliable.
Still present on 2.1.220, on Bedrock rather than Vertex (so this looks provider-independent), also driven by
anthropics/claude-code-actionon a Linux runner. Two datapoints that might help, since our failure looks like a variant of this rather than an exact match.1. A second failure mode: clean
end_turnrather than truncationOur stream doesn't truncate — we get a well-formed terminal envelope:
So instead of the harness killing the process mid-
tool_result, the model voluntarily ends its turn with a progress report about subagents that are still running. 13 subagents are abandoned (the last verdict file was written 2s before exit), exit code is 0, the job is green, and none of the downstream phases — which were supposed to apply edits and open a PR — ran. Same net impact as the original report, but reached by a different path, so it may not be fixed by whatever fixes the truncation.I suspect an interaction with this 2.1.211 entry:
That's right interactively. Under
-pthere's no user and no subsequent turn, so "reports the status of still-running agents" is the final answer, and the "waits for the real completion" half can never happen.2.
run_in_backgroundis no longer model-elected, so the prompt workaround has nothing to act onSame prompt, three versions, from our CI logs:
| Claude Code |
run_in_backgroundin Agent inputs |async_launched| outcome ||---|---|---|---|
| 2.1.131 | 22 | 22 | completed, PR opened |
| 2.1.195 | 0 | 0 | completed, PR opened |
| 2.1.220 | 0 | 20 | abandoned as above |
On 2.1.220 the model never passes
run_in_backgroundat all, yet every spawn returns"status": "async_launched"/"isAsync": true. Backgrounding is now implicit, so "instruct the model never to passrun_in_background" no longer has anything to target.Worth noting that 2.1.131 backgrounded 22 subagents explicitly and still completed normally — consistent with the 2.1.198 note that this was "previously a gradual rollout", and suggesting the regression isn't backgrounding itself but how the parent turn terminates around it.
CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MSalso doesn't appear to apply: exit came ~70s after the final spawn, well inside the 10-minute default.We're trying
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1next and will report back whether it holds on 2.1.220, given #69030 reports it being ignored for multi-subagent spawns.---
Update:
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1does work on 2.1.220Confirmed on the same 2.1.220 install that produced the failure above — same prompt, same runner, only the env var added:
| | before | with
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1||---|---|---|
|
Agenttool calls | 20 | 20 ||
async_launched/isAsync| 20 | 0 ||
num_turns| 28 | 85 ||
duration_ms(Claude step) | 188,598 | 518,967 || outcome | 13 subagents abandoned, no PR, exit 0 | all 20 verdicts collected, PR opened |
All 20 spawns ran synchronously and the orchestration completed end to end.
This doesn't contradict #69030, I think — that report is specifically about fork subagents (
CLAUDE_CODE_FORK_SUBAGENT), which it says background regardless of the variable. Ours are namedgeneral-purposesubagents spawned through theAgenttool, and for those the variable is honoured on 2.1.220. So the opt-out looks effective for Agent-tool spawns but not fork spawns.It's a workaround rather than a fix, though: it serialises the fan-out entirely (~2.8x wall clock here) so headless orchestration currently has to choose between parallel subagents and completing at all.