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

Resolved 💬 1 comment Opened May 9, 2026 by KingingWang Closed May 18, 2026

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).
  1. 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.
  1. 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).
  1. 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).
  1. 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_

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗