Responses WebSocket 101 response does not include x-codex-turn-state despite client replay support
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.rsdescribesx-codex-turn-stateas 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.rsattempts to capturex-codex-turn-statefrom the WebSocket handshake response header, and also fromresponse.metadataevent headers.codex-rs/codex-api/src/sse/responses.rshas the analogous HTTP/SSE response-header andresponse.metadatacapture path.
What steps can reproduce the bug?
- Use a valid ChatGPT-auth Codex account.
- Open a direct TLS socket to
chatgpt.comand send a WebSocket upgrade request to/backend-api/codex/responses. - 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-stateis still part of the protocol contract, the upstream should return it either in the initial WebSocket 101 response header or in a documentedresponse.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.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗