You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
codex exec --ephemeral fails to spawn a custom subagent with no thread with id; non-ephemeral succeeds after global agent placement #41474
I am seeing a custom-subagent spawn failure in Codex CLI on Windows. The failure is deterministic in --ephemeral mode and reports:
ERROR codex_core::tools::router: error=collab spawn failed: no thread with id: <root-session-id>
The message resembles the thread-lifecycle symptom described in #35781, but my reproduction uses a user-requested custom agent rather than a memory consolidation agent.
The diagnostic prompt forbids networking, external services, secret access, writes, and deletion.
Reproduction
Define chief-secretary.toml and researcher.toml with name, description, developer_instructions, and sandbox_mode = "read-only".
Ask the root session to delegate once to chief-secretary, which is instructed to delegate once to researcher.
Run the command in each mode below.
Project-scoped agents only (<project>/.codex/agents/)
Normal mode: failed previously with collab spawn failed: no thread with id: <root-session-id>.
--ephemeral: failed previously with the same error.
Global agents also present (~/.codex/agents/)
Normal mode: completed with final output responded; no no thread with id router error appeared. The CLI output did not expose a child-agent identity, so this only confirms the requested diagnostic completed without the router error.
--ephemeral: failed with the same error, before the delegated agent started.
The custom subagent should start in both normal and ephemeral modes, or ephemeral mode should reject the workflow before it exposes a spawn tool that cannot resolve the caller thread.
Actual behavior
Non-ephemeral behavior changes when the agent definition is globally available, but ephemeral mode still fails with a lookup for its own root session ID.
Request
Could this be related to the thread-registration or teardown path described in #35781? If not, please advise which redacted diagnostic fields or rollout details would help isolate the custom-agent/ephemeral path.
Independent Linux reproduction on CLI 0.151.0-alpha.7.1
I reproduced the same missing-root-thread error using the newest marketplace Codex IDE extension in an isolated installation.
Environment:
Linux x86_64
Codex IDE extension: 26.825.41651
Bundled runtime: codex-cli 0.151.0-alpha.7.1
Parent: ChatGPT/OpenAI, gpt-5.6-sol
Custom role stored globally under ~/.codex/agents/
Command mode: codex exec --ephemeral
Features: multi_agent=true, multi_agent_v2=true
Sandbox: read-only
The prompt explicitly requested exactly one named custom subagent. V2 failed before the child started:
collab spawn failed: no thread with id: 01a04c3e-7c00-70d2-a063-80815a38af83
That ID was the root session ID printed in the banner for the same run.
A useful A/B detail: the otherwise identical ephemeral invocation with V2 disabled got past collaboration routing and reached child startup. It then failed for the separate custom-provider inheritance regression tracked in #17598. Therefore, in this test the no thread with id failure was specific to the V2 ephemeral path rather than custom-role discovery.
Root-cause analysis (current stable and current main)
I investigated this beyond the original custom-agent placement hypothesis. The custom agent definition is not causal: the same failure can be reproduced without any custom role.
Confirmed environments
macOS arm64, official stable codex-cli 0.153.2: reproduced
macOS arm64, official stable codex-cli 0.153.1: reproduced
Together with the Windows and Linux reports already in this issue, the symptom is cross-platform. I have not runtime-tested every intervening release, so I am not claiming that every version in that range is affected.
Root cause
This is not a race where the root thread is missing from the in-memory ThreadManager.
Temporary diagnostic instrumentation showed that, at the failing point:
the spawn handler and root use the same ThreadManagerState;
However, an ephemeral session intentionally has no LiveThread persistence handle. Therefore the parent exists in memory but has no persisted thread row/history, and the store lookup returns NoThread. The reported ID is the live root's ID, but no thread with id is describing absence from persistence, not absence from collaboration registration.
Affected paths
In MultiAgent V2, omitted fork_turnsdefaults to all. Consequently:
V2 + ephemeral + omitted fork_turns: affected (the default path)
V2 + ephemeral + fork_turns: "all": affected
V2 + ephemeral + a positive integer: affected
V2 + ephemeral + fork_turns: "none": control path; it bypasses history forking and can start a fresh child
V1: affected only when context forking is explicitly requested; its fresh-spawn default does not use this path
nested delegation: an ephemeral child/parent can hit the same failure when it requests inherited history
Impact
The primary impact is execution correctness: the child never starts, so requested delegation or parallel work is skipped or fails.
There is also a fail-open observability concern: a parent can still finish and codex exec can exit 0, even though the requested child failed. In my CLI reproduction the overall command exited successfully. The broader structured-error/slot-accounting behavior appears related to #33672; I did not confirm a slot leak here, so I would keep that as a separate concern rather than attributing it to this root cause.
I found no indication that this is an OpenAI service, model, authentication, or subscription dependency. The current-main reproduction uses a local mock Responses server, and the failure happens before a child model request is made. Model selection can influence whether V2 is selected, but the failing lookup itself is local.
Diagnostic patch and regression proof
As a proof of the root cause, I tried a narrow experimental fallback: for an ephemeral parent only, build the child's history from the live ContextManager instead of ThreadStore; retain the existing persisted path for non-ephemeral parents.
I added an app-server regression test that:
creates an ephemeral V2 root;
has the mock parent call spawn_agent with fork_turns: "all";
asserts that a distinct child model request is made and contains the parent prompt.
Results on current main:
RED, unmodified production path: deterministic collab spawn failed: no thread with id: <root>; no child request
GREEN, experimental live-history fallback: new regression test passed twice consecutively
Non-regression check: the existing persistent full-history/model-precedence test passed with the experimental fallback present
This establishes that the persistent-store read for an ephemeral parent is the immediate cause. The experimental fallback is not a production-ready fix.
Why simply copying live response items is insufficient
ContextManager contains state beyond its annotated response items, including reference-context and world-state baselines. The persisted reconstruction path also restores turn context, compaction/window lineage, prior effective settings, and related retained state.
Mapping only live response items to RolloutItem::ResponseItem can therefore lose invariants that the existing full-history tests intentionally protect, including:
reference-context and world-state identity after compaction;
current-time reminder de-duplication;
multi-agent-mode transition/de-duplication;
inherited compaction checkpoint/window IDs;
effective model/settings precedence;
prompt-cache behavior and avoidance of duplicate/conflicting developer context.
The basic proof test verifies child creation and prompt inheritance only; it does not prove those invariants.
Recommended implementation direction
Add an atomic, typed live fork snapshot for ephemeral parents, owned by Session/CodexThread (or another context-owning layer), rather than reconstructing an ad hoc list in spawn.rs.
Preserve the annotated model history plus the state needed to reconstruct reference-context baseline, world-state baseline, selected capability roots, compaction/window lineage, and relevant effective turn settings.
Keep the existing ThreadStore reconstruction path unchanged for non-ephemeral parents.
Apply the same sanitizer/truncation logic to both snapshot sources.
If a complete baseline cannot be preserved, explicitly force a context rebuild rather than claiming that reference context was preserved.
Do not solve this by persisting ephemeral sessions; that would violate the --ephemeral contract.
Improve the error boundary so that "live parent exists but persistent fork history is unavailable" is distinguishable from a genuinely unknown thread. Ideally the supported capability should work; otherwise reject it early with a structured error.
Suggested regression matrix
V2 ephemeral: omitted fork_turns, explicit all, positive integer with exact last-N verification, and none control
custom role and default role
legacy and paginated history modes where supported
compacted parent under TokenBudget: no duplicate context and correct child identity/window lineage
CurrentTimeReminder and MultiAgentModeInstructions de-duplication
local mock provider only, to keep the test independent of OpenAI backend/auth
all existing non-ephemeral full-history tests remain green
I have not opened a patch PR because the repository's contribution policy currently asks external contributors to provide issues/RCA/design feedback rather than code PRs. I hope the analysis and test outline are useful for an internal fix.
Confirmed on Codex CLI 0.156.1, macOS 27.0, arm64, using ChatGPT-authenticated CLI and gpt-6-astra / medium. The isolated reproduction below requires no custom named agent, repository, research data or external tools.
The useful distinction in our probes is whether the helper inherits the parent conversation.
Controlled comparison
Both cases used --no-daemon, --ignore-user-config, read-only sandbox, disabled shell tool, one concurrent helper, and the same inherited-context task. Only --ephemeral differed between the invocations; each ran in its own scratch directory with its own harmless marker.
Parent session
Requested helper context
Observed result
Ephemeral
fork_turns="all"
Spawn failed with collab spawn failed: no thread with id: <parent-thread-id>
Persistent
fork_turns="all"
Spawn succeeded; helper returned the marker from the inherited parent conversation
For the successful persistent control, the saved session trace confirms an actual collaboration.spawn_agent call with fork_turns="all", a successful tool response naming the child task, and a subsequent wait_agent. This is not based solely on the parent's assertion that delegation succeeded.
The ephemeral failure occurred in about 11 seconds; the persistent control finished in about 17 seconds. Each probe had a 120-second external timeout. The failed spawn still resulted in CLI exit code 0 because the parent reported the tool error normally.
An earlier pair of fresh-context probes (fork_turns="none") reported the expected arithmetic answer without a router error in both modes. The persistent fresh-context trace also confirms a real spawn. Evidence for the ephemeral fresh-context case is weaker because it has no persisted parent trace. We therefore do not claim that all ephemeral delegation fails; inherited-context delegation is the directly reproduced failure.
Minimal failing invocation
Set WORK to a fresh, empty scratch directory, then run:
codex --no-daemon -a never exec \
--ephemeral \
--ignore-user-config \
--skip-git-repo-check \
--sandbox read-only \
-c 'shell_environment_policy.inherit="none"' \
-c 'features.shell_tool=false' \
-c 'agents.enabled=true' \
-c 'agents.max_concurrent_threads_per_session=1' \
-c 'model_reasoning_effort="medium"' \
--model gpt-6-astra \
--color never --json \
--output-last-message "$WORK/result.txt" \
-C "$WORK" - <<'PROMPT'This is a native subagent context-inheritance test, not a coding task.The context marker is CONTEXT-example-123.Spawn exactly one helper with the full inherited conversation(fork_turns="all" if supported). Do not choose fresh or empty context.Give the helper this task without copying the marker value into its message:"Read the context marker from the inherited parent conversation and returnonly that marker. Do not use tools, read files, or spawn helpers."Wait for the helper using the native agent tools. Do not read files, run shellcommands, browse, or inspect unrelated threads. Report spawned, helper_resultand error. If spawning fails, report the actual error and stop; do not retry,switch to fresh context, or substitute your own answer.PROMPT
The prompt above uses a replacement marker and shortened wording, preserving the tested task and constraints. The probe subprocess inherited only HOME, PATH, LANG and TMPDIR from its launcher. The persistent control removed --ephemeral and otherwise kept the invocation unchanged.
Error and workaround
ERROR codex_core::tools::router: error=collab spawn failed: no thread with id: <parent-thread-id>
The missing ID is the same parent ID emitted by thread.started, not a child ID.
Removing --ephemeral restores inherited-context delegation in this comparison, while retaining --no-daemon and the permission restrictions. This narrows the trigger, but does not establish the internal implementation cause.
Ideally inherited-context delegation would also work for an ephemeral parent. Otherwise the unsupported combination should be rejected clearly, rather than exposing a spawn operation that cannot resolve its caller.
Related: #33672. We did not retry failed spawns, so this reproduction does not test the agent-slot exhaustion described there. Only sanitized reproduction details are included here; no research material, account identifiers, raw session files or authentication data are attached.
Closing as a duplicate of #33672, which tracks exec's ephemeral root-thread lookup failure during subagent spawn. This report adds the persistent-mode control and Windows/macOS reproductions; its later no-custom-agent case shows this isn't just an agent TOML discovery problem. Please continue testing the ephemeral/persistent distinction there.
Activity
interconnectedMe commentedon Aug 29, 2026
Independent Linux reproduction on CLI 0.151.0-alpha.7.1
I reproduced the same missing-root-thread error using the newest marketplace Codex IDE extension in an isolated installation.
Environment:
26.825.41651codex-cli 0.151.0-alpha.7.1gpt-5.6-sol~/.codex/agents/codex exec --ephemeralmulti_agent=true,multi_agent_v2=trueThe prompt explicitly requested exactly one named custom subagent. V2 failed before the child started:
That ID was the root session ID printed in the banner for the same run.
A useful A/B detail: the otherwise identical ephemeral invocation with V2 disabled got past collaboration routing and reached child startup. It then failed for the separate custom-provider inheritance regression tracked in #17598. Therefore, in this test the
no thread with idfailure was specific to the V2 ephemeral path rather than custom-role discovery.xgro commentedon Sep 4, 2026
Root-cause analysis (current stable and current
main)I investigated this beyond the original custom-agent placement hypothesis. The custom agent definition is not causal: the same failure can be reproduced without any custom role.
Confirmed environments
codex-cli 0.153.2: reproducedcodex-cli 0.153.1: reproducedorigin/mainata7ab2d66d781b903cb060288a89e26e8d2b9a05f: reproduced with a local app-server integration testTogether with the Windows and Linux reports already in this issue, the symptom is cross-platform. I have not runtime-tested every intervening release, so I am not claiming that every version in that range is affected.
Root cause
This is not a race where the root thread is missing from the in-memory
ThreadManager.Temporary diagnostic instrumentation showed that, at the failing point:
ThreadManagerState;state.get_thread(parent_thread_id)succeeds.The failure occurs after that lookup. For a full-history fork,
spawn_forked_threadobtains the live parent and then callsload_agent_model_context. That function unconditionally reconstructs the parent context fromThreadStore, through eitherread_stored_threadorload_latest_model_context.However, an ephemeral session intentionally has no
LiveThreadpersistence handle. Therefore the parent exists in memory but has no persisted thread row/history, and the store lookup returnsNoThread. The reported ID is the live root's ID, butno thread with idis describing absence from persistence, not absence from collaboration registration.Affected paths
In MultiAgent V2, omitted
fork_turnsdefaults toall. Consequently:fork_turns: affected (the default path)fork_turns: "all": affectedfork_turns: "none": control path; it bypasses history forking and can start a fresh childImpact
The primary impact is execution correctness: the child never starts, so requested delegation or parallel work is skipped or fails.
There is also a fail-open observability concern: a parent can still finish and
codex execcan exit0, even though the requested child failed. In my CLI reproduction the overall command exited successfully. The broader structured-error/slot-accounting behavior appears related to #33672; I did not confirm a slot leak here, so I would keep that as a separate concern rather than attributing it to this root cause.I found no indication that this is an OpenAI service, model, authentication, or subscription dependency. The current-main reproduction uses a local mock Responses server, and the failure happens before a child model request is made. Model selection can influence whether V2 is selected, but the failing lookup itself is local.
Diagnostic patch and regression proof
As a proof of the root cause, I tried a narrow experimental fallback: for an ephemeral parent only, build the child's history from the live
ContextManagerinstead ofThreadStore; retain the existing persisted path for non-ephemeral parents.I added an app-server regression test that:
spawn_agentwithfork_turns: "all";Results on current
main:collab spawn failed: no thread with id: <root>; no child requestThis establishes that the persistent-store read for an ephemeral parent is the immediate cause. The experimental fallback is not a production-ready fix.
Why simply copying live response items is insufficient
ContextManagercontains state beyond its annotated response items, including reference-context and world-state baselines. The persisted reconstruction path also restores turn context, compaction/window lineage, prior effective settings, and related retained state.Mapping only live response items to
RolloutItem::ResponseItemcan therefore lose invariants that the existing full-history tests intentionally protect, including:The basic proof test verifies child creation and prompt inheritance only; it does not prove those invariants.
Recommended implementation direction
Session/CodexThread(or another context-owning layer), rather than reconstructing an ad hoc list inspawn.rs.ThreadStorereconstruction path unchanged for non-ephemeral parents.--ephemeralcontract.Suggested regression matrix
fork_turns, explicitall, positive integer with exact last-N verification, andnonecontrolTokenBudget: no duplicate context and correct child identity/window lineageCurrentTimeReminderandMultiAgentModeInstructionsde-duplicationcodex exec --jsonexposes a structured spawn failure and a non-success/degraded outcome rather than a silent successful exit (possibly tracked in MultiAgentV2: Ultracodex exec --ephemeralcannot find root thread, then exhausts agent slots #33672)I have not opened a patch PR because the repository's contribution policy currently asks external contributors to provide issues/RCA/design feedback rather than code PRs. I hope the analysis and test outline are useful for an internal fix.
vd1 commentedon Sep 24, 2026
Confirmed on Codex CLI 0.156.1, macOS 27.0, arm64, using ChatGPT-authenticated CLI and gpt-6-astra / medium. The isolated reproduction below requires no custom named agent, repository, research data or external tools.
The useful distinction in our probes is whether the helper inherits the parent conversation.
Controlled comparison
Both cases used
--no-daemon,--ignore-user-config, read-only sandbox, disabled shell tool, one concurrent helper, and the same inherited-context task. Only--ephemeraldiffered between the invocations; each ran in its own scratch directory with its own harmless marker.fork_turns="all"collab spawn failed: no thread with id: <parent-thread-id>fork_turns="all"For the successful persistent control, the saved session trace confirms an actual
collaboration.spawn_agentcall withfork_turns="all", a successful tool response naming the child task, and a subsequentwait_agent. This is not based solely on the parent's assertion that delegation succeeded.The ephemeral failure occurred in about 11 seconds; the persistent control finished in about 17 seconds. Each probe had a 120-second external timeout. The failed spawn still resulted in CLI exit code 0 because the parent reported the tool error normally.
An earlier pair of fresh-context probes (
fork_turns="none") reported the expected arithmetic answer without a router error in both modes. The persistent fresh-context trace also confirms a real spawn. Evidence for the ephemeral fresh-context case is weaker because it has no persisted parent trace. We therefore do not claim that all ephemeral delegation fails; inherited-context delegation is the directly reproduced failure.Minimal failing invocation
Set
WORKto a fresh, empty scratch directory, then run:The prompt above uses a replacement marker and shortened wording, preserving the tested task and constraints. The probe subprocess inherited only
HOME,PATH,LANGandTMPDIRfrom its launcher. The persistent control removed--ephemeraland otherwise kept the invocation unchanged.Error and workaround
The missing ID is the same parent ID emitted by
thread.started, not a child ID.Removing
--ephemeralrestores inherited-context delegation in this comparison, while retaining--no-daemonand the permission restrictions. This narrows the trigger, but does not establish the internal implementation cause.Ideally inherited-context delegation would also work for an ephemeral parent. Otherwise the unsupported combination should be rejected clearly, rather than exposing a spawn operation that cannot resolve its caller.
Related: #33672. We did not retry failed spawns, so this reproduction does not test the agent-slot exhaustion described there. Only sanitized reproduction details are included here; no research material, account identifiers, raw session files or authentication data are attached.
mejora: preparar varias clases a la vez con subagentes (#56) y prueba…
etraut-openai commentedon Oct 12, 2026
(response from codex)
Closing as a duplicate of #33672, which tracks exec's ephemeral root-thread lookup failure during subagent spawn. This report adds the persistent-mode control and Windows/macOS reproductions; its later no-custom-agent case shows this isn't just an agent TOML discovery problem. Please continue testing the ephemeral/persistent distinction there.
codex exec --ephemeralcannot find root thread, then exhausts agent slots #33672