`wait_agent` and `close_agent` report `completed: null` when a child `TurnComplete` contains an error

Open
#36,799 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
rust
Domain
backend, cli

Research direction

Start in codex-rs/core/src/agent/status.rs at agent_status_from_event, then read the related test in codex-rs/core/src/agent/control_tests.rs. Run the existing status test and add coverage for a TurnComplete event with an error. Done means errored status is preserved consistently by wait_agent, close_agent, notifications, and tool results.

Written by the indexing model from the issue text.

Description

bug CLI subagent

What version of Codex CLI is running?

codex-cli 0.146.0

What subscription do you have?

ChatGPT-authenticated Codex environment. The exact subscription tier is not
exposed by the diagnostics used for this report.

Which model were you using?

gpt-5.6-sol, high reasoning effort.

What platform is your computer?

Linux 6.17.0-1019-aws x86_64

What terminal emulator and version are you using?

Interactive Codex TUI. The terminal emulator is not relevant to this
reproduction.

Codex doctor report

Not included in this draft. The affected parent and child rollout records are
available and contain the complete lifecycle evidence.

What issue are you seeing?

A spawned child failed its first model request. Its terminal task_complete
event correctly contained an error and no final assistant message:

{
  "type": "task_complete",
  "last_agent_message": null,
  "error": {
    "message": "Item 'msg_<redacted>' of type 'message' was provided without its required 'reasoning' item: 'rs_<redacted>'.",
    "codex_error_info": "other"
  }
}

The same child then had three contradictory externally visible statuses:

subagent notification: errored(<actual API error>)
wait_agent:             completed: null
close_agent:            previous_status.completed: null

wait_agent also returned timed_out: false, so a caller can mistake a failed
child for a successfully completed child with an empty result.

Affected child thread:

019fc932-41a0-7201-90fb-a1a82d218364

What steps can reproduce the bug?

  1. Start Codex with MultiAgent V1 enabled.
  2. Spawn a child that reaches a terminal TurnCompleteEvent with
    error: Some(...) and last_agent_message: None. One deterministic way on
    0.146.0 is the currently reported fork_context=true reasoning-dependency
    failure from #33329.
  3. Call wait_agent for the child.
  4. Observe that the asynchronous child notification reports errored while
    wait_agent reports completed: null.
  5. Call close_agent for the same child.
  6. Observe that previous_status is also completed: null.

What is the expected behavior?

  • TurnCompleteEvent { error: Some(error), ... } must derive
    AgentStatus::Errored(error.message).
  • wait_agent must return the errored status and mark the wait tool call as
    failed.
  • close_agent.previous_status must report the same errored status.
  • Notifications, wait results, close results, and persisted lifecycle state must
    agree on the terminal outcome.

Additional information

Root cause

TurnCompleteEvent now has an optional terminal error field:

That field was added in
#32280 so unsuccessful turns can
carry terminal error details.

However, the multi-agent status reducer still maps every TurnComplete to
Completed(last_agent_message) and ignores ev.error:

EventMsg::TurnComplete(ev) =>
    Some(AgentStatus::Completed(ev.last_agent_message.clone())),

Both wait_agent and close_agent consume this derived watched status, which
explains why both return Completed(None) even though the terminal event carries
an error.

The status reducer predates TurnCompleteEvent.error. When #32280 added the
new field, its status test was updated only with error: None; no non-null error
case was added:

Suggested fix and regression coverage

Map an errored completion before the successful-completion case:

EventMsg::TurnComplete(ev) => match &ev.error {
    Some(error) => Some(AgentStatus::Errored(error.message.clone())),
    None => Some(AgentStatus::Completed(ev.last_agent_message.clone())),
},

Add tests that assert:

  1. TurnComplete(error=Some, last_agent_message=None) derives Errored.
  2. wait_agent returns that errored status and a failed collab tool status.
  3. close_agent.previous_status returns the same error.
  4. The asynchronous completion notification and tool results agree.
Duplicate search

No issue with this exact TurnCompleteEvent.error -> Completed(None) root cause
was found.

Related but distinct:

  • #25619 covers app-server
    turns that silently complete without a wire-visible error. In this case the
    terminal error is present; only the multi-agent status reducer discards it.
  • #34919 covers missing
    multi-agent event data in exec --experimental-json, not incorrect terminal
    status derivation.
  • #24342 covers waits that
    return no completed agents, not a known failed child being reported as
    Completed(None).
Dominant language
Rust
Stars
125k
Forks
19.5k
Avg merge
1m
Merged PRs (30d)
1k

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from openai/codex

All issues in openai/codex

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.