Background tasks spawned by subagents leak: no process, no handle, no way to clear
Claude Code 2.1.227, Windows 11, desktop app. Observed during a Workflow run of roughly 90 subagents across 7 runs.
What happens
A subagent calls Bash with run_in_background. The subagent finishes and returns its result. The background task keeps a live chip in the UI. Mine showed three, at 41 minutes:
Fetch older STAR foundry and HTS process PDFs Bash 41m
Check HYPRES mask release schedule staleness Bash 41m
Check SOEN-PDK repo metadata and licence Bash 41m
They are not running
I enumerated every process on the machine older than ten minutes matching bash|sh\.exe|curl|wget|python:
Get-CimInstance Win32_Process |
Where-Object { $_.Name -match 'bash|sh\.exe|curl|wget|python' -and $_.CreationDate -lt (Get-Date).AddMinutes(-10) }
No bash process of that age exists. The only long-lived hits were unrelated user scripts. The shells are gone; only the bookkeeping survived.
And they cannot be cleared from inside the session
TaskList in the orchestrator returns No tasks found. The tasks belong to subagent sessions that no longer exist, so TaskStop has no identifier to take. The orchestrator can see the consequence and not the cause.
Why this is worse than cosmetic
The failure mode is lost ownership, and the visible-but-dead chip is the benign half.
The malign half is a background shell that genuinely is still running — a hung fetch, a tail -f, a polling loop — spawned by an agent that has since exited. It holds a process, a socket and possibly a file handle. It is invisible to TaskList. Nothing in the session can reach it. You find it by noticing your machine is busy.
It scales with the thing it breaks
One orchestration run produced ~90 subagents; three leaked. That rate is tolerable at one agent and is not at a hundred. Multi-agent orchestration is precisely the mode where a human stops watching individual shells — which is the mode that most needs the runtime to reap them.
Asks, in order of value
- Scope the lifetime. A background task spawned by a subagent should be killed when that subagent completes, unless explicitly marked to outlive it. A subagent is a bounded unit of work; things it starts should be bounded by it.
- Re-parent instead, where outliving is intended. On subagent completion, surviving background tasks transfer to the orchestrator and appear in its
TaskList, soTaskStopcan reach them. Ownership must never become nobody's.
- Sweep on workflow completion. When a
Workflowrun ends, reap or re-parent everything its agents started, and report the count. Silent leakage reads as "everything finished".
- Reconcile the chip against reality. If the underlying process is gone, the chip should clear itself rather than showing a dead task as running for 41 minutes. A stale indicator trains people to ignore the indicator, which then hides the real one.
Scope of what was verified
Established: the processes are gone, and the orchestrator has no handle on the tasks.
Not established: which layer failed — reaping inside the subagent, ownership transfer, or only the UI chip. That is not visible from inside the session. The above is an observation and a request, not a claim about a specific code path.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗