Responses WebSocket 101 response does not include x-codex-turn-state despite client replay support

Open 💬 2 comments Opened Jun 29, 2026 by lyd123qw2008

What issue are you seeing?

Current Codex source still models x-codex-turn-state as a per-turn sticky-routing token that is learned from the server and replayed for subsequent requests in the same turn. However, a direct Responses WebSocket upgrade to the Codex upstream endpoint succeeds with 101 Switching Protocols but does not include x-codex-turn-state in the handshake response.

This is not a generic WebSocket connection failure: the upgrade succeeds and other upstream response headers are visible. In the same 101 response, x-models-etag and x-openai-proxy-wasm are present, but x-codex-turn-state is absent.

This makes the expected reconnect/retry behavior unclear. If the original WebSocket is lost during a turn, the client cannot replay a turn-state token that was never returned.

Relevant current source references from origin/main at ccdfb4f342:

  • codex-rs/core/src/client.rs describes x-codex-turn-state as a sticky-routing token received on turn start and replayed for subsequent requests in the same turn.
  • codex-rs/codex-api/src/endpoint/responses_websocket.rs attempts to capture x-codex-turn-state from the WebSocket handshake response header, and also from response.metadata event headers.
  • codex-rs/codex-api/src/sse/responses.rs has the analogous HTTP/SSE response-header and response.metadata capture path.

What steps can reproduce the bug?

  1. Use a valid ChatGPT-auth Codex account.
  2. Open a direct TLS socket to chatgpt.com and send a WebSocket upgrade request to /backend-api/codex/responses.
  3. Include the current Responses WebSocket beta header and turn metadata. Sensitive values below are redacted:
GET /backend-api/codex/responses HTTP/1.1
Host: chatgpt.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: <redacted>
Authorization: Bearer <redacted>
ChatGPT-Account-ID: <redacted>
OpenAI-Beta: responses_websockets=2026-02-06
Version: 0.142.3
User-Agent: codex-tui/0.142.3 (Ubuntu 24.04; x86_64) unknown (codex-tui; 0.142.3)
Originator: codex-tui
session_id: <redacted-uuid>
thread_id: <redacted-uuid>
session-id: <redacted-uuid>
thread-id: <redacted-uuid>
x-client-request-id: <redacted-uuid>
x-codex-window-id: <redacted-uuid>
x-codex-turn-metadata: <redacted-json>

Actual response summary from a live probe on 2026-06-29:

{
  "ok": true,
  "status": "HTTP/1.1 101 Switching Protocols",
  "request_beta": "responses_websockets=2026-02-06",
  "request_version": "0.142.3",
  "request_turn_metadata_present": true,
  "response_x_codex_turn_state_present": false,
  "response_x_models_etag_present": true,
  "response_x_openai_proxy_wasm_present": true
}

I also inspected WebSocket event frames for normal response.create traffic. The observed stream contained normal response lifecycle events, but no response.metadata event carrying headers["x-codex-turn-state"].

What is the expected behavior?

One of these should be true:

  • If x-codex-turn-state is still part of the protocol contract, the upstream should return it either in the initial WebSocket 101 response header or in a documented response.metadata.headers["x-codex-turn-state"] event early enough for same-turn reconnects/retries.
  • If this token has been deprecated, moved to another field, or replaced by a different sticky-routing mechanism, the client code/comments/tests should be updated to document the new expected behavior.

Additional information

I am filing this separately from generic WebSocket disconnect issues because the repro is specifically about the missing turn-state token. The connection itself upgrades successfully, and other response headers are observable, so this does not look like local header stripping.

For privacy, I redacted auth/account/session/thread identifiers and did not include codex doctor --json output because my local setup includes unrelated custom provider configuration. The protocol probe above was direct to chatgpt.com, not through that custom provider.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗