Skip to content

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

Open

Description

@sdro

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:

Activity

  1. added
    appIssues related to the Codex desktop app
    on Aug 14, 2026
  2. added
    bugSomething isn't working
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    tool-callsIssues related to tool calling
    on Aug 14, 2026
  3. victorherbst commented on Aug 27, 2026

    @victorherbst

    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:

    1. A thread targeted by an hourly heartbeat appeared in the UI as “Working for 27m 43s” while showing steps such as reading automation.toml.

    2. Thread inspection from another task reported the target as idle. Its latest scheduled turn had already completed successfully in 75.18 s, but it had no visible final assistant message.

    3. Three consecutive send_message_to_thread attempts used the correct local target and hostId: "local", but all failed with:

      Cannot steer conversation <redacted-thread-id> without an active turn id
      
    4. Navigating the app to the target thread and refreshing its status did not recover delivery.

    5. A later hourly heartbeat was able to create and complete another turn. After that scheduled wake, the same cross-thread follow-up operation succeeded again without changing the target ID or host.

    No task IDs, project paths, prompts, or user content are included here.

    Expected behavior:

    • When the destination is idle, send_message_to_thread should start a normal turn instead of trying only the steer path.
    • If a scheduled turn completes without a final assistant message, the UI should stop displaying “Working” and reconcile to the backend-completed state.
    • A heartbeat transition should not be required to repair cross-thread delivery.

    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.

  4. rparks1-eng commented on Sep 19, 2026

    @rparks1-eng

    Additional reproduction on Codex Desktop 26.915.31029 (build 9771), macOS, on 2026-09-19. This is the same idle-target failure, with local event timestamps that narrow the state transition:

    • A target turn completed at 17:29:26.813 UTC. The next target turn did not start until 17:44:40.649 UTC.
    • Three same-target send_message_to_thread calls failed at 17:29:10.831, 17:30:03.444, and 17:30:48.894 UTC with Cannot steer conversation <redacted-thread-id> without an active turn id. The first call overlapped the target-turn completion; the next two occurred while the target was idle.
    • A same-target call succeeded at 17:44:40.678 UTC, immediately after the target's next turn started, with no target-ID or host change. Subsequent calls also succeeded.

    This supports an inactive-turn/idle fallback or state-transition defect; it does not prove the internal root cause. The failure can silently strand a delegated request unless the caller retains intent, checks target-side receipt, reconciles before retry, and surfaces an unresolved failure. Please ensure an idle target starts a new turn, and return a queryable delivery result or receipt so callers can distinguish rejected delivery from delivered-but-error cases. No private thread IDs, prompts, project paths, or user content are included.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appbugSomething isn't workingsessionIssues involving session (thread) management, resuming, forking, naming, archivingtool-callsIssues related to tool calling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions