Codex CLI stream repeatedly reconnects then falls back after websocket closes before response.completed
Summary
Codex CLI can enter a repeated reconnect loop during a model turn when the WebSocket stream closes before response.completed. The UI retries up to 5/5, then falls back from WebSockets to HTTPS transport, but the user is left waiting in a degraded/stalled state instead of seeing a clean recovery, retry boundary, or actionable error.
This report is intentionally sanitized. The screenshots only show the generic transport error text and no private prompt/output data, so I am transcribing the visible messages rather than attaching session contents.
Environment
- Codex CLI:
codex-cli 0.142.5 - Platform: macOS arm64
- Model/profile visible in TUI:
gpt-5.5 xhigh - Invocation shape: interactive Codex CLI session resumed from local history
- Network/account details and private thread contents are intentionally omitted
Visible UI messages
The TUI showed repeated reconnect attempts:
Reconnecting... 3/5 (42s • esc to interrupt)
└ Stream disconnected before completion: websocket closed by server before response.completed
Then later:
Reconnecting... 5/5 (1m 04s • esc to interrupt)
└ Stream disconnected before completion: websocket closed by server before response.completed
After exhausting WebSocket reconnect attempts, the TUI showed:
⚠ Falling back from WebSockets to HTTPS transport. stream disconnected before completion: websocket closed by server before response.completed
Impact
- The active turn appears unreliable/stalled for over a minute.
- The user has to decide whether to interrupt, wait, or retry, without a clear state like “request recovered over HTTPS,” “request will be retried safely,” or “turn failed and no work is continuing.”
- In long-running or critical resumed sessions, this is risky because interrupting may alter goal/turn state while waiting can burn time and possibly usage.
Reproduction shape
I do not have a minimal synthetic repro, but the observed shape is:
- Resume an existing Codex CLI session.
- Start or continue a model turn using
gpt-5.5 xhigh. - During streaming, the WebSocket closes before
response.completed. - Codex shows reconnect attempts
3/5through5/5over about one minute. - Codex falls back from WebSockets to HTTPS transport with the same
websocket closed by server before response.completedmessage.
Expected behavior
- WebSocket-to-HTTPS fallback should be seamless if the request can continue safely.
- If continuation is not safe, the UI should mark the turn failed with an explicit terminal state and preserve the accepted user message.
- The UI should expose enough diagnostic detail to distinguish:
- transient transport reconnecting;
- successful fallback and continued stream;
- unrecoverable stream failure;
- detached/unknown backend turn still running.
- Interrupting during reconnect/fallback should not leave ambiguous goal/session state.
Actual behavior
- The UI shows repeated reconnect attempts and fallback text, but not a clear terminal or recovered state.
- The user sees a long stalled/reconnecting period and must manually decide whether to interrupt.
- The exact error text repeats:
websocket closed by server before response.completed.
Suggested fixes
- Add a clear post-fallback state: recovered over HTTPS, retrying safely, failed terminally, or backend state unknown.
- Show a request/turn diagnostic id in the UI or logs for this failure path.
- Preserve accepted user prompts and active goal state cleanly across reconnect/fallback/interrupt boundaries.
- Add an HTTPS-only or disable-WebSockets option for users/networks that repeatedly hit this condition.
- Avoid making
esc/interrupt the only practical recovery action when the backend turn state is uncertain.
Related issues
These look closely related, but I am filing this separately with current CLI/version details and the exact observed retry/fallback sequence:
- #22156
- #28115
- #26696
- #18960
- #20739
- #30777
Privacy note
No raw transcript, prompts, outputs, credentials, project names, or private paths are included here.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗