Subagents can shut down without delivering results; fork_turns none scouts acted as orchestrators

Open 💬 3 comments Opened Jun 6, 2026 by Allmight97

Summary

In Codex Desktop / MultiAgentV2, a parent thread spawned three read-only scout subagents with fork_turns: "none". The parent never received a final answer or mailbox result from any child. Repeated wait_agent calls timed out on schedule; list_agents later showed the children as shutdown; close_agent then returned thread <id> not found.

Local child rollout logs show the children were not merely idle. Despite self-contained read-only scout prompts, they appear to have acted like orchestration agents: they called wait_agent, attempted close_agent on sibling scouts, emitted commentary about other scouts not returning, and then their turns were interrupted/aborted. None delivered the requested scout findings to the parent.

This makes subagents unreliable for long planning/review/scout workflows: the parent cannot distinguish "still running," "shutdown without result," "lost mailbox result," "thread not found," or "child misinterpreted inherited orchestration context."

Environment

  • Variant: Codex Desktop / app-side multi-agent tools
  • CLI visible locally: codex-cli 0.137.0
  • Platform: macOS 26.6, Darwin 25.6.0 arm64
  • Account/subscription: ChatGPT Pro
  • Parent rollout/session:
  • /Users/jstar/.codex/sessions/2026/06/06/rollout-2026-06-06T13-43-41-019e9ead-5b80-7e40-8f53-ed9e915b86a4.jsonl
  • session id 019e9ead-5b80-7e40-8f53-ed9e915b86a4
  • Child rollout/session ids:
  • runtime/jobs scout: 019e9eb0-2d48-7dc3-93c8-ba9241c99566
  • frontend workflows scout: 019e9eb0-2ef6-72e3-a2b4-34eb785fdfd8
  • docs/contracts scout: 019e9eb0-30d3-7bb3-97d4-6cd2a34845ac

Reproduction shape

This was observed during a repo planning task where the parent tried to fan out read-only exploration scouts.

  1. In a parent Codex Desktop thread, first attempt to spawn multiple scouts with agent_type plus a full-history fork.
  2. Observe spawn validation error:
  • Full-history forked agents inherit the parent agent type, model, and reasoning effort; omit agent_type, model, and reasoning_effort, or spawn without a full-history fork.
  1. Retry with self-contained prompts and fork_turns: "none":
  • scout_runtime_jobs, agent_type: "explorer"
  • scout_frontend_workflows, agent_type: "explorer"
  • scout_docs_contracts, agent_type: "explorer"
  1. Attempt a fourth scout. It fails with:
  • collab spawn failed: agent thread limit reached
  1. Parent waits repeatedly:
  • wait_agent({"timeout_ms":30000}) -> timed out
  • wait_agent({"timeout_ms":60000}) -> timed out
  • wait_agent({"timeout_ms":90000}) -> timed out
  • wait_agent({"timeout_ms":180000}) -> timed out
  1. Parent checks agents:
  • Early list_agents showed the three scouts as running.
  • Later list_agents showed the three scouts as shutdown.
  • No final answer/mailbox payload had arrived in the parent.
  1. Parent tries to close them and gets:
  • collab tool failed: thread 019e9eb0-2d48-7dc3-93c8-ba9241c99566 not found
  • collab tool failed: thread 019e9eb0-2ef6-72e3-a2b4-34eb785fdfd8 not found
  • collab tool failed: thread 019e9eb0-30d3-7bb3-97d4-6cd2a34845ac not found

Evidence from parent rollout

From parent rollout /Users/jstar/.codex/sessions/2026/06/06/rollout-2026-06-06T13-43-41-019e9ead-5b80-7e40-8f53-ed9e915b86a4.jsonl:

  • Lines 26-29: first spawn attempts with agent_type + fork_turns: "all"; all returned the full-history fork validation error.
  • Lines 38-45: retry with fork_turns: "none"; three scouts spawned successfully and the fourth returned agent thread limit reached.
  • Lines 262-263: wait_agent 30s timeout.
  • Lines 286-287: wait_agent 60s timeout.
  • Lines 292-293: wait_agent 90s timeout.
  • Lines 298-299: wait_agent 180s timeout.
  • Lines 268-269: list_agents showed the three scouts as running.
  • Lines 304-309: close_agent returned thread <id> not found for all three child ids.
  • Lines 314-315: list_agents showed the three scouts as shutdown, still without any parent-delivered result payload.

Evidence from child rollouts

The child rollouts suggest this was not just slow/empty execution. The children appear to have drifted into orchestrator behavior and then aborted/interrupted.

  • Docs/contracts scout, child session 019e9eb0-30d3-7bb3-97d4-6cd2a34845ac:
  • called wait_agent({"timeout_ms":30000}), timed out
  • emitted commentary about scout threads still running
  • attempted close_agent on sibling scouts
  • close outputs reported aborted by user after 0.1s
  • turn ended with reason: "interrupted", duration about 279s
  • Frontend workflows scout, child session 019e9eb0-2ef6-72e3-a2b4-34eb785fdfd8:
  • called wait_agent({"timeout_ms":60000}), timed out
  • emitted commentary that scout agents did not return
  • attempted to close sibling/current scouts
  • one close output reported thread ... not found; another was aborted by user after 0.1s
  • turn ended with reason: "interrupted", duration about 326s
  • Runtime/jobs scout, child session 019e9eb0-2d48-7dc3-93c8-ba9241c99566:
  • called wait_agent({"timeout_ms":10000}), timed out
  • emitted commentary that the frontend/doc scouts had shut down
  • attempted close_agent on itself
  • close output reported aborted by user after 0.1s
  • turn ended with reason: "interrupted", duration about 375s

Expected behavior

  • A child spawned with fork_turns: "none" and a self-contained read-only prompt should treat that prompt as the active task and should not start coordinating sibling agents unless explicitly instructed.
  • If a child shuts down, is interrupted, or aborts before producing a normal final answer, the parent should receive a structured terminal event through wait_agent/mailbox.
  • wait_agent, list_agents, and close_agent should agree on lifecycle state or return a structured explanation of the mismatch.
  • thread <id> not found should not be the only close/readback signal for a thread that was previously spawned and visible through list_agents.
  • Thread capacity should be discoverable before spawn, or spawn_agent should return enough status on agent thread limit reached to recover cleanly.

Actual behavior

  • The parent received no usable scout content and no child final-answer payload.
  • wait_agent only returned timeouts, even though child turns later ended/interrupted.
  • list_agents transitioned from running to shutdown, but the parent still received no terminal child result.
  • close_agent returned thread <id> not found for each child.
  • Child rollouts show children calling orchestration tools (wait_agent, close_agent) instead of simply completing their assigned scout prompts.

Related issues checked

I did not find an exact duplicate for this combined failure mode: child shutdown/no parent-delivered final result + not found cleanup/readback + fork_turns: "none" scouts acting as orchestrators.

Adjacent issues:

  • #26728 - Subagent completion result can be lost after parent thread compaction
  • Closest on lost child completion, but in this case no explicit parent compaction was observed during the wait cycle, and the child logs show interruption/orchestration drift rather than a normal completed child result being hidden after compaction.
  • #24951 - multi_agent wait_agent/spawn_agent can block for ~7.5h; wait_agent timeout_ms not enforced during runtime stall
  • Related to wait/spawn control-plane reliability. Here, wait_agent did return on timeout; the problem is missing terminal/result delivery and ambiguous lifecycle state.
  • #25426 - close_agent can hang forever after marking a subagent closed if the child thread never terminates
  • Related lifecycle/close problem. Here, close did not hang; it returned thread <id> not found after the parent had seen the children as spawned/listed.
  • #23479 - Main agent needs subagent capacity/status preflight before spawn_agent attempts
  • Related to the fourth scout failing with agent thread limit reached and no clear preflight/capacity status.
  • #23930 - Codex app subagent cards can remain stuck/visible after close while close/readback reports no live agent
  • Related readback mismatch. This report is specifically about tool-level parent mailbox/result delivery and lifecycle status.
  • #26130 - Parallel spawn_agent children can receive sibling prompt envelopes with fork_turns none
  • Related isolation issue. This report does not prove sibling prompt-envelope leakage, but it does show children behaving as sibling orchestrators despite fork_turns: "none" and narrow scout prompts.

Impact

This makes subagents brittle for exactly the workflows where they are most valuable: parallel repo scouting, review/audit variance reduction, long-running research branches, and delegated planning. The parent thread cannot rely on subagent output unless a final payload actually arrives, and the failure mode consumes time/context while leaving no trustworthy result.

For user-facing Codex Desktop behavior, this feels like subagents silently disappearing or becoming confused about their role. It also makes it hard to file precise bug reports because parent-visible state and child-local state disagree.

Suggested fix direction

  • Strengthen the active task boundary for spawned children, especially fork_turns: "none" children with role-scoped prompts. Parent/team orchestration instructions should not cause a child to manage sibling agents unless that is explicitly delegated.
  • Always deliver a child terminal state to the parent mailbox, even if there is no final answer: completed, interrupted, aborted, shutdown_without_result, not_found_after_spawn, etc., with child thread id and last known status.
  • Make wait_agent able to surface terminal status updates for shutdown/interrupted children, not only final answer payloads.
  • Reconcile list_agents and close_agent states. If a listed/shutdown child has no live thread, return a structured already_shutdown / not_found_but_spawn_was_recorded signal instead of a generic thread not found failure.
  • Expose capacity/status preflight before spawning, or include active capacity and live child list in the agent thread limit reached response.
  • Add regression coverage for:
  • fork_turns: "none" child with a narrow scout prompt must not call wait_agent/close_agent unless the prompt asks it to.
  • child interrupted after startup must generate a parent-visible terminal event.
  • parent wait_agent must observe child terminal events.
  • list_agents/close_agent lifecycle consistency after child shutdown or interrupted turn.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗