send_message_to_thread intermittently fails to start a turn when the target thread is idle
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 <redacted-thread-id> 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?
- Open an existing Codex thread.
- Open a side chat associated with that work.
- Allow the main thread's active turn to finish so the thread is idle.
- From the side chat, ask Codex to send a benign follow-up to the main thread.
- Codex invokes the equivalent of:
``json``
{
"threadId": "<redacted-main-thread-id>",
"hostId": "local",
"prompt": "Benign follow-up message"
}
- Observe that send_message_to_thread can return:
````
Cannot steer conversation <redacted-thread-id> because its active turn already ended
- 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:
- The
send-follow-up-messagehandler first attempts the steer path. - If that throws
SteerTurnInactiveError, the handler is intended to catch it and start a normal turn. - The follower/owner request bridge reconstructs returned errors using the equivalent of
Error(i.error). - That reconstruction discards the original error name.
- The fallback predicate recognizes either an error named
SteerTurnInactiveErroror a message containing that identifier. - 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:
1 Comment
Additional reproduction from Codex Desktop 26.820.60940 (build 7119) on macOS 26.5.1 (25F80), arm64.
This appears to be the same inactive-turn fallback bug, with an automation/heartbeat and UI-state desynchronization dimension:
automation.toml.idle. Its latest scheduled turn had already completed successfully in 75.18 s, but it had no visible final assistant message.send_message_to_threadattempts used the correct local target andhostId: "local", but all failed with:``
text
``Cannot steer conversation <redacted-thread-id> without an active turn id
No task IDs, project paths, prompts, or user content are included here.
Expected behavior:
idle,send_message_to_threadshould start a normal turn instead of trying only the steer path.This strengthens the race/fallback hypothesis in the original report and suggests the Desktop UI may also retain stale “Working” state when a scheduled turn completes without a final message.