anthropics / anthropics/claude-code
[BUG] Agent task notification reports status=completed for an agent still waiting on its own background task
- Langage dominant
- Python
- Étoiles
- 145k
- Forks
- 23.1k
- Métriques de merge des PR
- Métriques de PR en attente
Description
### Preflight Checklist
- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) 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?
When a subagent starts a background task (`Bash` with `run_in_background: true`) and then ends its turn to wait, the parent immediately receives a `` with `status=completed` and a summary saying the agent "finished".
The agent has not finished. It is re-invoked when its background task completes and carries on working — I measured 109 seconds and then 46 seconds, both unprompted, with nothing sent to it.
Three things in that envelope are false or misleading, and each independently pushes the parent toward killing a live agent:
1. **`status=completed`, and the summary word "finished".** Genuine completion and parking are the same string, so the true state cannot be represented.
2. **The ``:** *"A task-notification fires each time this agent stops with no live background children of its own."* One was live. This is worse than an omission — it tells the reader the true state is impossible, so "it might still be working" is not a hypothesis they weigh and reject, but one they are instructed to rule out.
3. **`` holds the agent's last utterance.** Under `status=completed`, a field named `result` containing "I'll stop polling now and wait…" reads unambiguously as an agent that announced a next step and then died before taking it. The utterance is honest; the framing manufactures the wrong reading.
The one contrary signal in the envelope is that the usage counters rise between successive "completed" notifications for the same task — 99124 tokens / 12 tool uses, then 104094 / 16. That is easily read as a waste loop rather than as work in progress.
**Consequence in practice:** the parent concluded the agent had died without producing anything, called `TaskStop` on it two seconds after it had in fact reported success, and redid the work. Before that, believing the agent dead, it started its own copy of the same build in the same working tree — so two builds were writing to one output directory, one of them running `clean` over files the other was reading.
### What Should Happen?
A parked agent should be distinguishable from a finished one, without the reader needing to infer anything. In rough order of how much each would help:
1. **A live-children count that can be non-zero**, or a note reading "1 background task still running; you will be notified again". One field, no judgement required, and it makes waiting obviously right and killing obviously wrong.
2. **A status that is not `completed`** — `parked`, `waiting`, `idle`. Reserve `completed` for terminal states.
3. **Don't put a parking utterance in ``.** `none — agent has not produced a final report` would be correct and sufficient. A field named `result` makes a claim about what it contains.
4. **Sanction a status check for agent tasks.** `TaskOutput(task_id=…, block=false, timeout=30000)` already answers this — its description says it "Retrieves output from a running or completed task" and that `block=false` gives a "non-blocking check of current status" — but it is headed `DEPRECATED`, and of its three per-type bullets the `local_agent` one is the only one that redirects to a different tool ("use the Agent tool result directly. Do NOT Read the .output file"). The prohibition is on reading the *file*, not on calling the *tool*, but the single bullet addressed to agent tasks is the one that steers away from the only tool that answers the question. Either un-deprecate it for this use or say plainly in that bullet that calling it is fine.
5. **Tell subagents that a backgrounded task re-invokes them.** See Additional Information — as it stands they have grounds to believe stopping may mean never waking.
### Error Messages/Logs
```shell
There is no error. The defect is a well-formed notification asserting a false state. The envelope, with identifiers removed:
…
completed
Agent "…" finished
A task-notification fires each time this agent stops with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.
I'll stop polling now and wait for the background build's completion notification before proceeding.
9912412357035
At that moment the agent's own background task was still running; it completed 109 seconds later, at which point the agent resumed on its own.
```
### Steps to Reproduce
Minimal example — no project files needed.
1. In any session, spawn an agent with a task that backgrounds something slow and then reports:
Run `sleep 150` as a background Bash task (run_in_background: true). Then tell me its task id and stop; report the result once it finishes.
2. The agent starts the background task and ends its turn — after, in my case, several filler tool calls it visibly did not want to make (see Additional Information).
3. **Within a few seconds**, the parent session receives a `` with `status=completed`, a summary saying the agent "finished", and the agent's last sentence in ``. The `sleep` is still running.
4. **After the sleep completes**, the agent is re-invoked with nothing sent to it, reports, and ends its turn again — producing a *second* `status=completed` notification for the same task id, with higher usage counters than the first.
5. From the parent, at step 3, `TaskOutput(task_id=…, block=false, timeout=30000)` is the only thing that distinguishes this from a finished agent. Note that `block` and `timeout` are listed in `required` despite carrying defaults, so `TaskOutput(task_id=…)` alone is malformed.
### Claude Model
Opus
### Is this a regression?
I don't know
### Last Working Version
_No response_
### Claude Code Version
2.1.260 (Claude Code)
### Platform
Anthropic API
### Operating System
Windows
### Terminal/Shell
Other
### Additional Information
**Why the agent makes filler calls before stopping, and why this is not a Model Behavior issue.** Before writing this I asked a fresh subagent to quote every instruction it holds bearing on ending turns, background tasks, polling, and what its final message is for. It found **no instruction against ending a turn**. What it did find explains the behaviour completely:
- Its prompt says *"respond with a concise report … the caller will relay this to the user"* and *"Return findings directly as your final assistant message — the parent agent reads your text output, not files you create."* So for a subagent, **parking and reporting are the same act** — there is no way to pause without emitting something that will be consumed as the report. This is also exactly how a parking sentence comes to occupy a `result` field.
- Nothing tells it that ending its turn is safe. `Bash` says `run_in_background` *"re-invokes you when it exits"*; `PowerShell` says the same parameter means *"you'll be notified"*; nothing states these are one mechanism. And `Artifact` says *"Only an interactive or SDK main-loop session holds a watch (not a subagent, teammate, background, or print session)"* — positive evidence that some background facilities exclude subagents.
So the agent had reason to fear that stopping meant never waking, and no way to pause without reporting. In my case it made seven filler calls over 35 seconds — `echo "waiting…"`, `echo "idle"`, `jcmd -l`, `echo "standing by…"`, `echo "no further polling…"` — its own reasoning stating each time that it should stop instead. That is a rational response to its instructions, not a model defect.
**`Monitor` is not an alternative route.** Its own description sends this case away from itself: *"One ('tell me when the server is ready / the build finishes') → use Bash with `run_in_background`"*. The documented route for a single completion is the one that produces the misleading notification, and there is no sanctioned substitute.
**On the regression question and the version field.** I could not answer this from disk. The `` text above appears identically in both 2.1.258 and 2.1.260, the two versions present on this machine, so it is not a change between those two — but I have not tested whether the *behaviour* differs, and the defect may predate both. Related: the `Agent` tool description text I quote does not appear in either CLI binary, so part of what I am quoting is served by the desktop app rather than by the CLI, and the version above may not identify the component that needs the fix.
**On the two dropdowns.** Platform is the Anthropic API: neither `CLAUDE_CODE_USE_BEDROCK` nor `CLAUDE_CODE_USE_VERTEX` is set, there are no `AWS_*` or `GOOGLE_*` variables, `ANTHROPIC_BASE_URL` resolves to an `anthropic.com` host, and the model id is the bare first-party form. Terminal/Shell is "Other" because none of the options applies — **this is the Claude Code desktop app, with no terminal involved at all.** For the environment that does matter here: Windows 11, the Bash tool resolving to Git Bash, and the app's own Terminal panel being PowerShell though it plays no part in this. Worth noting because two of the related issues above are Windows-specific, and one of them names exactly that PowerShell-primary, Git-Bash-for-Bash-tool configuration.
**Impact, stated fairly.** The discarded result was not merely complete but correct — an uncontended re-run afterwards matched it exactly — so the cost here was a redone build rather than a wrong answer. The failure mode is general in two directions though: any parent that trusts a `completed` notification will kill live agents, and any parent that then redoes the work risks contending with the very task it believes has ended. The second is the more dangerous, because it puts two writers in one working tree.
**Verified vs inferred.** Verified: every quoted string, from live tool descriptions and notification envelopes; the 109-second and 46-second unprompted re-invocations; that `TaskOutput`'s `block` and `timeout` are in `required`. Inferred, and not established: that the child task is not accounted to the agent for the purposes of the "no live background children" test. The child's own completion notification also appeared in the parent's stream, which is consistent with that, but I did not establish the mechanism.
**Not a duplicate of the three issues surfaced for this text.** All three are the *inverse* defect — a wake that fails to arrive — whereas this is a wake that arrived correctly while the notification to the parent asserted a false state.
- **#88001** (macOS, 2.1.235, open): the notification is lost, and only after the coordinator messages the agent mid-run. Nothing was sent to the agent here.
- **#91503** (Windows 11, 2.1.258, open): a subagent's queued completion has no idle-wake consumer, so the subagent hangs until nudged — measured as enqueued for 2m59s with no dequeue. That is the opposite of what happened here: the agent was re-invoked twice, at 109 and then 46 seconds, with nothing sent to it.
- **#76594** (Windows 11, 2.1.207, closed as not planned): the same scenario as this one — a subagent that parked while its own background Bash task was running — but with the wake enqueued and then removed undelivered, so it never resumed.
One thing in that comparison is worth raising rather than leaving for someone to notice: **this observation on 2.1.260 contradicts #91503's on 2.1.258**, same platform and the same shell configuration. Either an idle-wake consumer arrived between those two versions, or the wake here was incidental — the parent in this episode was continuously active throughout, and #91503 describes the subagent hanging "until something else gives it a turn", which a busy parent's queue activity could plausibly supply. I cannot distinguish those two from a single session and am not claiming either. Neither affects this report, whose claim is about the *contents* of the notification the parent received rather than about whether the agent woke.
**Filed separately:** `ListAgents` instructs you to call a tool named `SendMessage` that does not resolve. That is what left the parent with no way to act on its (wrong) conclusion, and so contributed to this incident, but it is an independent defect with an independent fix.
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Piste de recherche
Start by reproducing the minimal case in Claude Code 2.1.260: spawn an agent that runs `sleep 150` as a background Bash task, then inspect the parent `task-notification` and `TaskOutput(..., block=false, timeout=30000)`. The payload names no files or tests, so first locate the code that emits task notifications and agent results. Done means parked agents with live background work are not reported as completed or final results.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- ai-infra-agents, bash, cli, powershell
- Domaine
- ai-infra-agents, cli, developer-experience
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- Active
- Clarté
- Plutôt claire
- Accessibilité débutants
- 45/100