openai / openai/codex

send_message_to_thread intermittently fails to start a turn when the target thread is idle

Open
#38,609 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

app bug session tool-calls
Dominant language
Rust
Stars
125k
Forks
19.5k
PR merge metrics
PR metrics pending

Description

What version of the Codex App are you using (From “About Codex” dialog)?

26.803.61601 (build 6396)

What subscription do you have?

Pro

What platform is your computer?

macOS 26.5.2 (25F84), Apple Silicon Darwin 25.5.0 Darwin Kernel Version 25.5.0: Tue Jun 9 22:28:34 PDT 2026; root:xnu-12377.121.10~1/RELEASE_ARM64_T6041 arm64 arm

What issue are you seeing?

A Codex side chat intermittently cannot send a follow-up message to an idle main thread using send_message_to_thread.

The main thread and side chat are displayed in the same Codex window. The target thread is local and reported as idle. The call uses the correct thread ID and hostId: "local", but returns:

Cannot steer conversation because its active turn already ended

The operation should not fail merely because the destination is idle. The same cross-thread operation has succeeded on other attempts, making delivery unreliable and state-dependent.

No thread IDs, prompts, project paths, or other personal information are included in this report.

What steps can reproduce the bug?
  1. Open an existing Codex thread.

  2. Open a side chat associated with that work.

  3. Allow the main thread's active turn to finish so the thread is idle.

  4. From the side chat, ask Codex to send a benign follow-up to the main thread.

  5. Codex invokes the equivalent of:

    {
      "threadId": "<redacted-main-thread-id>",
      "hostId": "local",
      "prompt": "Benign follow-up message"
    }
    
  6. Observe that send_message_to_thread can return:

    Cannot steer conversation <redacted-thread-id> because its active turn already ended
    
  7. The intended new turn does not begin.

The behavior is intermittent. The same tool and destination can work on other attempts.

What is the expected behavior?

send_message_to_thread should handle both destination states:

  • If the destination has an active turn, deliver the message using the supported active-turn follow-up behavior.
  • If the destination is idle, start a normal new turn.

A race in which the destination finishes while delivery is being prepared should also fall back safely to starting a new turn instead of returning an inactive-steer error.

Additional information

Inspection of the JavaScript bundled with Codex App 26.803.61601 suggests a likely error-handling defect:

  1. The send-follow-up-message handler first attempts the steer path.
  2. If that throws SteerTurnInactiveError, the handler is intended to catch it and start a normal turn.
  3. The follower/owner request bridge reconstructs returned errors using the equivalent of Error(i.error).
  4. That reconstruction discards the original error name.
  5. The fallback predicate recognizes either an error named SteerTurnInactiveError or a message containing that identifier.
  6. The surfaced message contains only “Cannot steer conversation … because its active turn already ended”, so the predicate may not recognize it and the fallback does not run.

This is a likely explanation for the intermittent behavior, although I did not capture internal ownership telemetry for the failed call.

Suggested fix:

  • Preserve structured error codes or names across the follower/owner bridge.
  • As defensive handling, recognize the inactive-turn message and fall back to starting a normal turn.
  • Retain the fallback even if destination state is checked earlier, because the active turn can finish between the check and delivery.

Related but apparently not duplicate:

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.

Research direction

Start by tracing the send-follow-up-message handler and the follower/owner request bridge in the bundled JavaScript. Inspect how returned errors are reconstructed and how the inactive-turn fallback is recognized, then reproduce the idle and race cases. Done means an idle destination starts a new turn and an active destination still receives its follow-up without an inactive-steer error.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, rust
Domain
backend-api-design, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.