Responses WebSocket connect failures wait through all stream retries before HTTP fallback

Open 💬 10 comments Opened Apr 27, 2026 by weidapao
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

Many users behind proxies, especially in mainland China, see Codex print Reconnecting... 1/5 through 5/5 at the start of a turn before it finally begins responding. A practical workaround reported in #14297 is to define a custom provider with supports_websockets = false, which makes Codex use HTTP/SSE immediately.

I investigated the code path and prepared a small patch in my fork:

Root Cause

The default OpenAI provider supports Responses WebSocket transport. When the local/proxy environment cannot carry WebSocket traffic correctly, WebSocket connect fails with timeout/network errors. Today those failures are treated like retryable stream failures, so the turn loop consumes the full stream_max_retries budget before activating HTTP fallback.

This matches user logs from #14297: every attempt is transport="responses_websocket"; after Reconnecting... 5/5, Codex logs falling back to HTTP, then the HTTP Responses request completes quickly.

Proposed Change

Fallback to HTTP/SSE immediately when Responses WebSocket connection setup fails with:

  • TransportError::Timeout
  • TransportError::Network(_)

Keep the existing behavior for established stream failures and for explicit 426 Upgrade Required fallback.

The patch adds a small helper:

fn should_fallback_to_http_after_websocket_connect_error(error: &ApiError) -> bool {
    matches!(
        error,
        ApiError::Transport(TransportError::Timeout | TransportError::Network(_))
    )
}

and applies it in both WebSocket preconnect/prewarm and normal turn-time WebSocket connection setup.

Why This Helps

Users whose proxies do not support WebSocket/TUN routing should no longer wait through all 5 reconnect attempts before Codex switches to the HTTP path that already works for them. Users with working WebSocket transport should continue using WebSocket as before.

Test Coverage

The fork adds a regression test that simulates a WebSocket handshake timeout and asserts Codex performs only one WebSocket attempt before using HTTP/SSE successfully.

cargo test -p codex-core websocket_fallback_switches_to_http_on_connect_timeout -- --exact

I could not complete the test locally on my Windows machine because the environment is missing the MSVC linker link.exe, but formatting and git diff --check passed locally.

View original on GitHub ↗

10 Comments

github-actions[bot] contributor · 2 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #19804

Powered by Codex Action

etraut-openai contributor · 2 months ago

Web sockets provide many performance benefits over HTTP, so we really don't want to use the fallback unless it's really necessary. I don't think that an immediate fallback on first error would serve most customers well.

Is there no way you can configure your proxy to support web socket connections? Which proxy are you using? Perhaps you can work with the maintainers to get this limitation removed?

picasso250 · 2 months ago

I am seeing the same pattern in codex: the WebSocket retries through Reconnecting... 1/5 ... 5/5, then the HTTP fallback works normally.

One thing I am trying to understand: does the Responses WebSocket transport currently respect proxy environment variables such as HTTP_PROXY / HTTPS_PROXY, or the WebSocket-specific WS_PROXY / WSS_PROXY? In my local setup the proxy itself appears to support WebSocket tunneling over HTTP CONNECT, and regular HTTPS traffic through the proxy works, so it is not obvious whether the failing path is the proxy or whether the WS client path is bypassing proxy env handling.

If the WebSocket path does not currently share the same proxy handling as the HTTP path, could Codex either add that support or expose a ChatGPT-auth-compatible config option to force HTTPS/SSE transport / disable Responses WebSocket? That would avoid the repeated fixed delay for environments where HTTP fallback is consistently the working path.

echograil · 2 months ago

环境:Windows 10/11 + ChatGPT OAuth
现象:每次启动 hello 卡 75 秒(5×15s WebSocket 重试)
UI 误导:显示「Timeout waiting for child process to exit」
日志真凶:responses_websocket + stream disconnected - retrying sampling request
workaround:自定义 HTTP-only provider + supports_websockets = false
改进建议:

修 UI 错误文案,别把 WS 失败包装成子进程超时
提供 CLI / config 直接禁用 WebSocket 的开关(不用新建 provider)
缩短 WebSocket 失败重试次数(5×15s = 75s 太长了,2×5s 也够判定)

kostysh · 1 month ago

The same pattern in Codex for the last 3-4 days: the WebSocket retries through Reconnecting... 1/5 ... 5/5, then the HTTP fallback works normally.

xieshuaix · 27 days ago

Same issue, not fixed, this occurs not only for the first query on startup, but also for every subagent launched right after previous query succeeds (so this issue is definitely state-dependent), essentially adding a delay of 1min+ for every attempt to establish a fresh connection.

According to Codex itself:
Current source opens a direct TCP/TLS connection using tokio_tungstenite::connect_async_tls_with_config without consulting macOS proxy settings or proxy environment variables (source). respect_system_proxy only configures selected HTTP/auth clients.
So probably why ChatGPT for Mac works fine for me but Codex doesn't is because Codex doesn't respect OS proxy for wss.

But according to https://github.com/openai/codex/issues/13041, this can also happen without proxy.
so I doubt this is only a proxy-related issue or just some bugs with server or client side wss implementation.

Some mentioned forcing ipv4 instead of ipv6 might solve the issue: https://github.com/openai/codex/issues/13406#issuecomment-4169251271, but in my case, that does not work.

Also, I think a better timing to try to handshake with server than posting query is when clicking on conversation tab or when first typing query (Google does this anticipatory trick), that may reduce the wait time, giving a smoother experience that you otherwise have to squeeze out of your GPU cluster by optimizing time till first token.

simfor99 · 24 days ago

Adding another data point, because this does not seem limited to pure proxy/connect-timeout cases.

Environment:

  • Codex CLI 0.142.2
  • WSL2 Ubuntu via Windows Terminal
  • Built-in OpenAI provider / ChatGPT auth, model gpt-5.5, high reasoning
  • No HTTP_PROXY / HTTPS_PROXY env vars in the shell at the time of inspection

Observed behavior:

  • TUI showed Reconnecting... 5/5 for several minutes, then fell back to HTTP(S).
  • Warning text was: Falling back from WebSockets to HTTP(S) transport: stream disconnected before completion: failed to send websocket request: IO error: Broken pipe (os error 32).
  • HTTP/SSE fallback succeeded and the turn completed.
  • In one affected long-running session, the local transcript was about 623 MB / 12,050 JSONL lines, with roughly 222k input tokens against a 258,400 context window.
  • That turn recorded time_to_first_token_ms around 295,506 (~4m56s) and full turn duration around 386,761 ms.
  • The conversation had accumulated large generated JSON/HTML/prompt/trace/tool-output artifacts, so this was a large request / high-context case.

Why this issue looks like the same root problem:
The user-visible cost is paying the full WebSocket retry budget before an HTTP/SSE path that works. In this case the failure was a send-side broken pipe rather than a plain connect timeout, but the desired behavior is the same: for transport/network-class WebSocket failures, fail over to HTTP/SSE much earlier.

Request:
Please include send-side Broken pipe / network write failures in the fast HTTP fallback path, and make the TUI message clearly identify this as a transport fallback rather than making users debug local task execution.

gaopengbin · 6 days ago

I built a small Windows workaround for this: https://github.com/gaopengbin/chatgpt-proxy-launcher

It gives ChatGPT/Codex a process-scoped HTTP proxy without enabling global proxy mode. This fixed the repeated Reconnecting... 1/5–5/5 behavior in my test.

fireattack · 6 days ago

For Windows at least, the root cause of this issue is that codex cli for whatever reason (spaghetti code? different lib used for different protocols and they have different default behaviors?) doesn't respect system proxy for its WSS protocol requests but DOES for its HTTPS requests.
But interestingly it (WSS requests) DOES respect environment variables. So, simply set HTTPS_PROXY=http://localhost:xxxx before running codex will immediately fix it.

| Connection Type | Respects System Proxy <br>(a.k.a. Internet Options) | Respects System Environment Variables <br>(e.g., HTTPS_PROXY) |
| :--- | :--- | :--- |
| HTTPS Requests | Yes | Yes |
| WSS (WebSocket) Requests | No | Yes |

Charles-Zhu · 5 days ago

Adding a macOS Codex Desktop data point and a slightly different feature request.

Environment:

  • macOS
  • Codex CLI / bundled app backend 0.144.4
  • Local system proxy; normal HTTPS requests work, while WebSocket connectivity can be intermittent

The desired behavior is not necessarily HTTP-only or WebSocket-only. An adaptive transport policy would be more useful:

  1. Prefer HTTPS/SSE when recent WebSocket connection attempts have timed out or disconnected.
  2. Fall back to WebSocket if HTTPS/SSE fails, or periodically probe WebSocket again.
  3. Cache the last successful transport for the current network/session.
  4. Reset the preference after a network change or configurable cooldown.
  5. Avoid paying the complete Reconnecting... 1/5 through 5/5 WebSocket retry budget on every turn when HTTPS/SSE is already known to work.

A configurable transport order and a small circuit breaker would preserve WebSocket performance where it is reliable while making unstable proxy networks recover quickly. For example:

transport_preference = ["https", "websocket"]
transport_failure_threshold = 1
transport_probe_cooldown_seconds = 300

The currently exposed feature list in 0.144.4 shows responses_websockets and responses_websockets_v2 as removed, so there does not appear to be a supported user-facing way to express this policy today.