Codex Desktop stalls on an existing long-running thread: WebSocket closes before response.completed, while HTTP fallback returns 200 OK but produces no stream events

Open 💬 1 comment Opened Jul 11, 2026 by Kinghammer1

What version of the Codex App are you using (From “About Codex” dialog)?

ChatGPT/Codex Desktop: 26.707.41301 (CFBundleVersion 5103)

What subscription do you have?

Plus

What platform is your computer?

Mac intel X86

What issue are you seeing?

Codex Desktop stalls on an existing long-running thread: WebSocket closes before response.completed, while HTTP fallback returns 200 OK but produces no stream events

Environment

  • ChatGPT/Codex Desktop: 26.707.41301 (CFBundleVersion 5103)
  • Bundled Codex CLI: 0.144.0-alpha.4
  • macOS: 15.7.3 (24G419)
  • Model: gpt-5.6-sol
  • Reasoning effort: medium
  • Authentication: ChatGPT authentication
  • Endpoint: https://chatgpt.com/backend-api/codex/responses
  • Local proxy: Clash Verge mixed port at 127.0.0.1:7897
  • Clash mode: Global for traffic explicitly sent to the local proxy
  • System proxy: disabled
  • TUN: disabled
  • ChatGPT/Codex is launched with proxy environment variables pointing to 127.0.0.1:7897

Summary

An existing, long-running Codex Desktop thread frequently becomes stuck with no visible UI progress.

New threads can send and receive messages normally using the same application process, account, model, proxy endpoint, and local network. The problem is reproducible mainly on one existing development thread.

The local development processes remain alive while the Codex turn is stuck. The failure occurs in the model response transport:

  • With WebSocket enabled, the connection successfully upgrades but is later closed before a response.completed event is received.
  • With WebSocket disabled, the HTTP Responses request returns 200 OK with chunked transfer encoding, but no response events arrive. After several minutes, Codex opens another request.
  • During the stall, the UI timer continues increasing, but no new reasoning, tool call, file change, or completion event appears.

User-visible error

Reconnecting 1/5

stream disconnected before completion:
websocket closed by server before response.completed

In HTTP mode, the UI does not always show an explicit error. It simply remains on the last completed file edit while the elapsed-time counter continues increasing.

Steps to reproduce

  1. Open an existing Codex Desktop thread with a long development history.
  2. Use ChatGPT authentication and a provider configured for the Responses API.
  3. Route the ChatGPT/Codex processes through a local HTTP proxy.
  4. Ask Codex to continue a multi-step implementation task.
  5. Observe that Codex may complete some file edits and then stop producing visible progress.
  6. Wait several minutes.

Actual behavior

WebSocket transport

The WebSocket handshake succeeds:

INFO codex_api::endpoint::responses_websocket:
successfully connected to websocket:
wss://chatgpt.com/backend-api/codex/responses

connection: upgrade
upgrade: websocket
sec-websocket-extensions: permessage-deflate
cf-cache-status: DYNAMIC

The stream is later disconnected before completion:

WARN codex_core::responses_retry:
stream disconnected - retrying sampling request (1/5 ...)

User-visible error:
websocket closed by server before response.completed

Codex reconnects successfully, but the same turn may disconnect again without receiving response.completed.

HTTP Responses transport

WebSocket support was disabled with:

[model_providers.custom]
name = "OpenAI"
requires_openai_auth = true
supports_websockets = false
wire_api = "responses"

Codex successfully connects to the local proxy:

DEBUG hyper_util::client::legacy::connect::http:
connecting to 127.0.0.1:7897

DEBUG hyper_util::client::legacy::connect::http:
connected to 127.0.0.1:7897

The Responses endpoint returns successfully:

DEBUG codex_http_client::default_client:
Request completed
method=POST
url=https://chatgpt.com/backend-api/codex/responses
status=200 OK

headers:
transfer-encoding: chunked
connection: keep-alive
server: cloudflare

However, no meaningful stream events follow:

No response.in_progress
No response.output_item.*
No tool call
No response.completed

Approximately three minutes later, Codex creates another HTTP connection and receives another 200 OK, again without producing visible output.

Timeline from one stalled turn

Thread ID:

019f4ee9-31c9-70b1-bf28-a69d7cb5399e

Turn ID:

019f501a-c824-7ae0-bd8f-284332e0b628

Sanitized timeline:

15:37:04  Connecting to HTTP proxy 127.0.0.1:7897
15:37:04  Proxy connection established
15:37:04  HTTP/1 connection ready
15:40:08  POST /backend-api/codex/responses returned 200 OK
15:40:08  No response stream events followed
15:41:00  Another proxy connection was opened
15:41:01  HTTP connection became ready

During this interval, the UI remained unchanged.

Local process state during the stall

The application and project services remained alive:

Codex app-server: alive
local-agent-server.mjs: alive
holdem-lab development server: alive
esbuild service: alive
Cloudflare workerd development process: alive

The relevant Codex and Chromium helper processes had established TCP connections to:

127.0.0.1:7897

This indicates that the local development server did not cause the UI stall.

Comparison with new threads

A newly created thread works normally through the same proxy configuration.

This suggests that the issue may depend on one or more of the following:

  • Existing thread state or incremental request state
  • Long-running Responses streams
  • WebSocket reuse behavior
  • HTTP chunked-stream handling after headers are received
  • Idle timeout or retry behavior when no response event arrives
  • Proxy interaction with long-lived WebSocket or HTTP streaming connections

The cumulative tokens_used value for the affected thread is high, but this value should not be interpreted as the context size of a single request.

Expected behavior

After the endpoint returns 200 OK, Codex should either:

  1. continue receiving and displaying stream events;
  2. detect a stream idle timeout and retry with a clear diagnostic;
  3. fall back to another transport; or
  4. terminate the turn with an actionable error.

The UI should not remain indefinitely on the last file edit while only the elapsed-time counter changes.

Questions for maintainers

  1. Is there a configurable stream idle timeout for the Desktop app?
  2. Can the client log the exact WebSocket close code and close reason?
  3. Can the HTTP client distinguish “headers received but no SSE events” from an active model response?
  4. Should the HTTP transport automatically retry when no stream event arrives within a defined interval?
  5. Could an existing thread’s incremental-response or WebSocket reuse state cause this behavior?
  6. Is there a supported way to disable WebSocket only for proxied sessions without editing the provider definition globally?

Additional note

The raw diagnostic logs contain authentication-related response headers and Cloudflare cookies. They should not be uploaded publicly without redaction.

What steps can reproduce the bug?

repley

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 ↗