# Codex Desktop turn stays in “Thinking” after WebSocket stream disconnects with `Broken pipe`

Open 💬 1 comment Opened Jul 12, 2026 by Kinghammer1

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

lasted

What subscription do you have?

Plus

What platform is your computer?

Mac X86

What issue are you seeing?

Codex Desktop turn stays in “Thinking” after WebSocket stream disconnects with Broken pipe

Summary

In an image-heavy Codex Desktop thread, a new turn is accepted successfully but produces no assistant output, tool call, timeout, or visible error. The UI remains in “Thinking” indefinitely.

The turn eventually surfaced this concrete transport error:

stream disconnected before completion: failed to send websocket request: IO error: Broken pipe (os error 32)

This confirms that the response stream disconnected before completion. The main user-facing problem is that the thread can remain stuck in “Thinking” for a long time before surfacing the failure, and retrying in the same thread repeatedly reproduces it.

The same thread can repeatedly enter this state after the user interrupts and retries. Restarting/retrying the turn does not reliably recover it.

Environment

  • Codex Desktop / ChatGPT app version: 26.707.51957 (CFBundleVersion 5175)
  • macOS: 15.7.3 (24G419)
  • Host: local
  • Thread type: local project thread
  • Thread contained several image-generation results
  • Session JSONL size at reproduction time: 53,364,477 bytes across 394 JSONL records

Steps to reproduce

  1. Use a local Codex project thread for a long image/UI-design workflow.
  2. Generate several images in the same thread. The session history stores large inline image-generation payloads.
  3. After the earlier image work completes, send a simple text-only question, for example: “Is SVG or PNG easier to edit?”
  4. Observe that turn/start returns successfully.
  5. Wait. No reasoning item, assistant message, tool call, completion event, timeout, or user-visible error appears. The UI continues to show “Thinking”.
  6. Interrupt and send “continue” or retry the question. The new turn may exhibit the same behavior.

Expected behavior

  • The simple text-only question should receive a response, or
  • the client should compact/prune oversized image payloads before submitting context, or
  • the turn should fail within a bounded time and show a useful error with a retry/recover action.

Actual behavior

  • turn/start succeeds immediately.
  • The turn remains active with no output.
  • One reproduction remained silent for about 19 minutes until manually aborted.
  • Subsequent retries were also silent until manually aborted.
  • No error is attached to the affected turn in the thread UI/state.
  • A later error reports a failed WebSocket write with Broken pipe (os error 32).

Timeline from the session log (UTC)

2026-07-12T09:57:07.460Z task_started  019f55c2-56f8-7241-a08e-6310a43c98e1
2026-07-12T09:57:07.480Z user_message  [simple text-only question]
# No assistant/reasoning/tool event for ~19 minutes
2026-07-12T10:16:16.972Z turn_aborted  019f55c2-56f8-7241-a08e-6310a43c98e1

2026-07-12T10:16:21.489Z task_started  019f55d3-f2ee-7150-b123-ba8f3938f19b
2026-07-12T10:16:21.512Z user_message  continue
# No assistant/reasoning/tool event
2026-07-12T10:17:34.044Z turn_aborted  019f55d3-f2ee-7150-b123-ba8f3938f19b

2026-07-12T10:17:37.950Z task_started  019f55d5-1d9c-7d73-93c1-3c736d731348
2026-07-12T10:17:37.971Z user_message  continue
# No assistant/reasoning/tool event
2026-07-12T10:17:46.974Z turn_aborted  019f55d5-1d9c-7d73-93c1-3c736d731348

2026-07-12T10:17:49.324Z task_started  019f55d5-4a09-7de2-90f4-22fd2ca6b0e8
2026-07-12T10:17:49.346Z user_message  [same simple text-only question]
# Turn remained active with no output

Desktop log confirms the request was accepted:

2026-07-12T09:57:07.448Z ... method=turn/start ... durationMs=1 errorCode=null ...
2026-07-12T10:16:21.486Z ... method=turn/start ... durationMs=1 errorCode=null ...
2026-07-12T10:17:37.948Z ... method=turn/start ... durationMs=1 errorCode=null ...
2026-07-12T10:17:49.322Z ... method=turn/start ... durationMs=2 errorCode=null ...

Additional network symptoms

Shortly after the stuck turn began, the desktop log also recorded transport/certificate failures:

chatgpt_pubsub_transport_closed
sa_server_request_failed errorMessage=net::ERR_CERT_AUTHORITY_INVALID routePattern=/wham/tasks/list
sa_server_request_failed errorMessage=net::ERR_CONNECTION_CLOSED routePattern=/celsius/ws/user
chatgpt_pubsub_connection_failed errorMessage=net::ERR_CONNECTION_CLOSED

These errors may be related, but they began after the first turn had already been silent for many minutes. The primary bug is that a successfully started turn can remain indefinitely active without output, timeout, or a visible error, regardless of whether the underlying cause is oversized context, connection failure, or server-side processing.

The most specific error eventually shown for the affected workflow was:

stream disconnected before completion: failed to send websocket request: IO error: Broken pipe (os error 32)

Broken pipe indicates that the WebSocket/underlying socket was already closed when the client attempted to write. The client should detect this promptly, terminate the active turn, expose a retryable error, and ideally reconnect/retry safely.

Suspected contributing factor

The affected session JSONL is about 53 MB despite having only 394 records, because image-generation results include very large inline payloads. This may cause context preparation/upload/compaction to stall. This is an inference, not a confirmed root cause.

It may be worth checking whether image bytes are accidentally retained in the model context or repeatedly serialized during subsequent text-only turns instead of being represented by compact file/reference metadata.

Requested improvements

  1. Do not include full inline generated-image bytes in subsequent model context when a compact reference is sufficient.
  2. Add progress/timeout handling between accepted turn/start and the first model event.
  3. Surface transport, certificate, WebSocket Broken pipe, context-size, and compaction failures promptly in the thread UI.
  4. Allow a stuck turn to recover without requiring a new thread.
  5. Add diagnostic fields for context byte size, upload state, compaction state, and server request ID.
  6. On WebSocket disconnect, mark the turn failed instead of leaving it indefinitely active, and provide a safe reconnect/retry path.

Attachments

  • Sanitized relevant log excerpt: github-issue-new-ui-stuck-log.txt
  • Full raw session log is intentionally not attached because it contains prompts, local paths, and large inline image data.

What steps can reproduce the bug?

noway,only new window

What is the expected behavior?

Codex Desktop version: 26.707.51957 (5175)
macOS: 15.7.3 (24G419)
Session JSONL: 53,364,477 bytes; 394 records

=== Affected turn timeline (UTC, sanitized) ===
2026-07-12T09:57:07.460Z event_msg task_started 019f55c2-56f8-7241-a08e-6310a43c98e1
2026-07-12T09:57:07.480Z event_msg user_message [simple text-only question]
2026-07-12T10:16:16.972Z event_msg turn_aborted 019f55c2-56f8-7241-a08e-6310a43c98e1

2026-07-12T10:16:21.489Z event_msg task_started 019f55d3-f2ee-7150-b123-ba8f3938f19b
2026-07-12T10:16:21.512Z event_msg user_message continue
2026-07-12T10:17:34.044Z event_msg turn_aborted 019f55d3-f2ee-7150-b123-ba8f3938f19b

2026-07-12T10:17:37.950Z event_msg task_started 019f55d5-1d9c-7d73-93c1-3c736d731348
2026-07-12T10:17:37.971Z event_msg user_message continue
2026-07-12T10:17:46.974Z event_msg turn_aborted 019f55d5-1d9c-7d73-93c1-3c736d731348

2026-07-12T10:17:49.324Z event_msg task_started 019f55d5-4a09-7de2-90f4-22fd2ca6b0e8
2026-07-12T10:17:49.346Z event_msg user_message [same simple text-only question]
[No subsequent assistant, reasoning, tool, completion, timeout, or error event]

=== Desktop app-server acknowledgements ===
2026-07-12T09:57:07.448Z info method=turn/start conversationId=019f5087-635c-7882-b54e-be58337d790f durationMs=1 errorCode=null
2026-07-12T10:16:21.486Z info method=turn/start conversationId=019f5087-635c-7882-b54e-be58337d790f durationMs=1 errorCode=null
2026-07-12T10:17:37.948Z info method=turn/start conversationId=019f5087-635c-7882-b54e-be58337d790f durationMs=1 errorCode=null
2026-07-12T10:17:49.322Z info method=turn/start conversationId=019f5087-635c-7882-b54e-be58337d790f durationMs=2 errorCode=null

=== Later transport symptoms ===
User-visible error from the affected workflow:
stream disconnected before completion: failed to send websocket request: IO error: Broken pipe (os error 32)

2026-07-12T10:19:47.641Z warning chatgpt_pubsub_transport_closed
2026-07-12T10:19:50.221Z warning sa_server_request_failed errorMessage=net::ERR_CERT_AUTHORITY_INVALID routePattern=/wham/tasks/list status=500
2026-07-12T10:19:51.926Z warning sa_server_request_failed errorMessage=net::ERR_CONNECTION_CLOSED routePattern=/celsius/ws/user status=500
2026-07-12T10:19:51.926Z warning chatgpt_pubsub_connection_failed errorMessage=net::ERR_CONNECTION_CLOSED retryCount=1
2026-07-12T10:20:00.702Z warning chatgpt_pubsub_connection_failed errorMessage=net::ERR_CERT_AUTHORITY_INVALID retryCount=2

Privacy note: prompts, local paths, request headers, image bytes, and unrelated log entries were omitted.

Additional information

_No response_

View original on GitHub ↗

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