Nested subagents: children spawned by a subagent are always async (regardless of run_in_background), completion notifications never reach the subagent parent, and TaskStop fails with ownership errors after resume
Environment
- Claude Code v2.1.201, macOS (Darwin 27.0.0), CLI + desktop session
- Reproduced across models (Opus 4.8 and Fable 5 orchestrators, Sonnet children)
Summary
When an agent spawned via the Agent tool (an "orchestrator" subagent) spawns its own children via the Agent tool, three related failures occur reliably. We ran a controlled experiment (10+ orchestrator runs over two days) and can share reproduction data.
1. Children are effectively async regardless of run_in_background
Even when the orchestrator's Agent call does not set run_in_background (or sets it to false/null), the child runs detached: the orchestrator's turn does not block on it, no completion notification is delivered to the orchestrator, and the orchestrator is never auto-resumed. Transcript inspection shows run_in_background: null on the calls, yet the parent proceeded and later ended its turn "waiting for the child's completion notification" — which never arrives. Result: the orchestrator stalls permanently unless externally poked.
- Frequency: in our first experiment round, all 4 of 4 orchestrator runs (2 models × 2 tasks) stalled at least once with "I'll wait for the implementer's completion notification".
- Docs mismatch: the docs suggest the top-level subagent's summary returns to the caller; for nested spawns nothing returns to the intermediate parent.
2. Child completion notifications are misdelivered to the main conversation
When the child finishes, its completion notification (task-notification) is delivered to the main conversation that spawned the orchestrator — not to the orchestrator that actually spawned the child. We observed 6+ instances. The orchestrator meanwhile believes the child is still running.
3. TaskStop fails with ownership errors after a SendMessage resume
If the main conversation resumes a stalled orchestrator via SendMessage ("was stopped; resumed it"), the resumed orchestrator can no longer stop children it spawned before the resume: TaskStop fails with an ownership/permission error (observed in 3 of 4 runs that attempted it). The un-stoppable child keeps writing to the shared working tree, racing the parent.
Minimal reproduction sketch
- Main conversation: spawn orchestrator O via
Agent(run_in_background: true). - O's prompt: "delegate an implementation task to a child via the Agent tool (foreground), then verify its result".
- O spawns child C without
run_in_background. - Observe: O's turn continues immediately (C is detached); O ends its turn stating it will wait for C.
- C completes → notification arrives in the main conversation, not in O. O never resumes.
- Main resumes O via SendMessage → O attempts
TaskStopon C → ownership error.
Workaround that eliminated the stalls for us
Prompting orchestrators with a "delegation set" removed the stalls completely (0 stalls in 4 subsequent runs, vs 4/4 + 3 more in control runs):
- children must write their report to an agreed absolute path (write to a temp name, then
mvto the final name for atomicity), - the parent runs a bounded foreground wait loop in the same turn (
for i in $(seq 1 60); do [ -f REPORT ] && break; sleep 15; done), - never end a turn depending on a child's completion; on timeout, checkpoint and continue solo (children can't be stopped anyway).
This works but burns a foreground Bash slot for polling; native completion delivery to the spawning parent would remove the need.
What we can provide
Timestamped transcripts (JSONL) for all runs showing: run_in_background: null spawns behaving async, stall messages, misdelivered notifications (with origin.kind metadata), and TaskStop ownership errors. Happy to share extracted excerpts.
Related issues
- #69212 (open) — overlaps with symptom 2 here (notification misrouting). This issue adds symptoms 1 (always-async nested children) and 3 (TaskStop ownership errors after resume), plus controlled-experiment frequency data and a prompting workaround.
- #69249 (closed as duplicate of the above).
This issue has 10 comments on GitHub. Read the full discussion on GitHub ↗