Skip to content

TUI: resolve_elicitation routed to wrong thread_id on multi-session race condition #21894

@KingingWang

Description

@KingingWang

What version of Codex CLI is running?

0.130

What subscription do you have?

pro

Which model were you using?

No response

What platform is your computer?

No response

What terminal emulator and version are you using (if applicable)?

No response

What issue are you seeing?

Bug Description

When multiple Codex sessions (threads) are active in the TUI, a resolve_elicitation request can be routed to the wrong session, causing an elicitation request not found error and leaving the TUI in a hung state.

Root Cause

In codex-rs/tui/src/chatwidget.rs, the function handle_elicitation_request_now uses self.thread_id.unwrap_or_default() (the currently active UI thread) instead of params.thread_id (the thread that actually generated the elicitation request):

pub(crate) fn handle_elicitation_request_now(
    &mut self,
    request_id: AppServerRequestId,
    params: McpServerElicitationRequestParams,
) {
    ...
    let thread_id = self.thread_id.unwrap_or_default();  // ← BUG: should use params.thread_id
    ...
}

The McpServerElicitationRequestParams struct already carries the correct thread_id set by the app-server, but it is ignored throughout the function. The same bug affects:

  1. AppLinkViewParams::from_url_app_server_request — receives wrong thread_id
  2. McpServerElicitationFormRequest::from_app_server_request — receives wrong thread_id
  3. The fallback ApprovalRequest::McpElicitation — receives wrong thread_id
  4. The McpServerElicitationRequest::Url auto-decline path — sends resolve_elicitation to the wrong thread

Reproduction Steps

  1. Open a Codex TUI session (thread A) and let it complete a turn
  2. Start a second review session (thread B) that triggers an MCP elicitation
  3. The elicitation request from thread B gets routed to thread A because self.thread_id still points to A
  4. Thread A's session handler has no pending elicitation for this request, so resolve_elicitation fails with elicitation request not found
  5. TUI becomes unresponsive

Log Evidence

2026-05-09T06:36:37.565253Z  WARN session_loop{thread_id=019e0b71-...}:submission_dispatch{...op="resolve_elicitation"...}: codex_core::session::handlers: failed to resolve elicitation request in session error=elicitation request not found

The elicitation originated from thread 019e0b73 (new review session), but resolve_elicitation was delivered to thread 019e0b71 (old completed session).

Suggested Fix

Replace self.thread_id.unwrap_or_default() with params.thread_id (parsed to ThreadId):

// Before:
let thread_id = self.thread_id.unwrap_or_default();

// After:
let thread_id: ThreadId = params.thread_id.parse()
    .unwrap_or_else(|_| self.thread_id.unwrap_or_default());

Affected Code

  • codex-rs/tui/src/chatwidget.rshandle_elicitation_request_now (line ~4603)
  • Same pattern may exist in handle_request_user_input_now and handle_request_permissions_now — should be audited

Introduced By

Commit f9a907aebe — "Support Codex Apps auth elicitations (#19193)"

What steps can reproduce the bug?

  1. Start a TUI session (Thread A): Open the Codex TUI and complete one or more conversation turns so that Thread A becomes the currently active thread (self.thread_id = A).

  2. Open a second session (Thread B): Within the same TUI process, initiate a new operation that creates a second thread — for example, by using /review or /approve on a PR — but keep the TUI UI focus on Thread A.

  3. Trigger an MCP Elicitation: Have Thread B execute an operation that causes an MCP server to issue an elicitation request (e.g., an MCP tool call that requires connector authentication or user input).

  4. Observe the routing error: When the TUI receives the elicitation request from Thread B, handle_elicitation_request_now incorrectly uses self.thread_id (which is Thread A) instead of params.thread_id (which is Thread B).

  5. Elicitation resolution fails: When the user tries to respond to the elicitation, resolve_elicitation is sent to Thread A's session handler. Since Thread A has no pending elicitation matching this request, it fails with:

    failed to resolve elicitation request in session error=elicitation request not found
    

    The TUI then becomes unresponsive.

Key condition: Multiple active sessions exist in the TUI simultaneously, and the currently displayed thread (self.thread_id) differs from the thread that actually generated the elicitation.

What is the expected behavior?

No response

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal displaybugSomething isn't workingmcpIssues related to the use of model context protocol (MCP) servers

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions