[BUG] Usage-limit-terminated subagent is recorded as status: completed and rendered as "Done"
Preflight Checklist
- [x] Searched existing issues (#78231 covers the discarded-output/billing angle; #73990 is the docs gap). Neither covers the success-status misreport below.
- [x] Single bug report
- [x] Latest version (2.1.220)
What's Wrong?
When a session usage limit terminates a foreground subagent, the Agent tool returns a successful tool result. The transcript records toolUseResult.status: "completed" and omits is_error, so the UI renders the killed agent as "Done" alongside its tool-use and token counts.
This contradicts the documented behavior in sub-agents.md:
Foreground: if a rate limit, overload, or server error cuts off a subagent that already produced output, the Agent tool returns that partial output with a note that the subagent was cut off and didn't finish its task. Otherwise the tool call fails with Agent terminated early due to an API error.
Observed: the tool call does not fail. It takes the "already produced output" path and succeeds — even though the only recovered output is the agent's preamble sentence, emitted before it made a single tool call.
Concrete case (3 independent occurrences, transcripts on disk):
| Session | Agent | Tool uses | Tokens | Recovered payload |
|---|---|---|---|---|
| A | Explore | 25 | 67,570 | "I'll explore these components in parallel." (42 chars) |
| B | Explore | 25 | 74,102 | preamble sentence only |
| B | Explore | 30 | 68,910 | preamble sentence only |
Raw structure of the returned tool result (session A):
{
"toolUseResult": {
"status": "completed",
"agentType": "Explore",
"totalTokens": 67570,
"totalToolUseCount": 25,
"toolStats": { "bashCount": 25 },
"content": [
{ "type": "text", "text": "Agent terminated early due to an API error: You've hit your session limit · resets 4:20pm (Asia/Taipei)\n\nEverything below is PARTIAL output recovered from the agent before it was cut off. The agent did NOT finish its task — treat these results as incomplete." },
{ "type": "text", "text": "I'll explore these components in parallel." }
]
}
}
Note the is_error field is absent from the tool_result content block entirely.
Two user-visible consequences:
- The UI lies. The screen showed
2 Explore agents finished · Done · Donewhile one of those agents had been killed 60 seconds earlier with zero work product. A user watching the terminal has no way to tell a completed agent from a killed one.
- The "PARTIAL output recovered" preamble is self-contradictory in this state. It promises recovered partial output, then attaches a sentence the agent emitted before doing any work. 25 tool calls of retrieval produced nothing recoverable. If nothing meaningful can be recovered, the "partial output" framing actively misleads both the model and the user into thinking some findings survived.
What Should Happen?
- A subagent terminated by a usage limit should not be recorded as
status: "completed", and the UI should not label itDone. Mark it failed/terminated so it is visually distinguishable. - The "partial output recovered" path should only be taken when there is actual post-tool-call output to recover. Preamble text emitted before the first tool call is not partial findings — in that case the tool call should fail cleanly, as the docs already specify.
Steps to Reproduce
Preconditions: an account close enough to a session limit that it will be crossed during a fan-out.
- In Claude Code CLI, dispatch 2+ foreground
Exploresubagents in a single Agent tool block on a task requiring substantial exploration. - Allow the session limit to be crossed while the agents are in flight.
- Observe the terminal: killed agents render as
Donewith their tool-use and token counts intact. - Inspect the session transcript at
~/.claude/projects/<project>/<session>.jsonl— the corresponding entry hastoolUseResult.status: "completed"and nois_error, with acontentarray whose second block is the agent's preamble.
Claude Model
Opus (claude-opus-5)
Is this a regression?
I don't know — the surrounding behavior changed in v2.1.199/v2.1.200 (per the changelog and #73990), so this may be an edge case introduced by that fix.
Claude Code Version
2.1.220 (Claude Code)
Platform
Anthropic API (Claude Pro subscription, session limit)
Operating System
macOS
Terminal/Shell
Other (tmux + fish)
Additional Information
Related: #78231 reports the same underlying discard-on-termination behavior from Cowork with a monthly spend limit, focused on the billing impact. #73990 documents that the "no output at all" path is under-specified. This report is specifically about the success status and Done label on a terminated agent, which neither covers.
The practical risk this creates: in a fan-out where some agents survive and some are killed, the surviving agents' reports look comprehensive, and the killed ones are labeled Done. Nothing in the UI signals that the exploration was incomplete before the parent proceeds to act on it.