Detect dead websocket connections faster after network changes instead of showing `Working` for up to 5 minutes

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

What version of Codex CLI is running?

codex-cli 0.118.0

What subscription do you have?

pro

Which model were you using?

_No response_

What platform is your computer?

it is platform independent

What terminal emulator and version are you using (if applicable)?

_No response_

What issue are you seeing?

When the network changes underneath an active Codex session, for example switching VPNs or after resuming from sleep, the TUI can keep showing Working for 5 minutes even though the underlying websocket is effectively dead.

The websocket response stream is considered dead only after stream_idle_timeout_ms, which defaults to 300000 ms (5 minutes).

Relevant code:

  • codex-rs/model-provider-info/src/lib.rs
  • DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300_000
  • DEFAULT_STREAM_MAX_RETRIES = 5
  • DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS = 15_000
  • codex-rs/codex-api/src/endpoint/responses_websocket.rs
  • run_websocket_response_stream() waits with tokio::time::timeout(idle_timeout, ws_stream.next())
  • codex-rs/core/src/codex.rs
  • retry UI for websocket reconnects is partially hidden in release builds on the first retry

Because of that, a silent network break can look like a healthy in-progress turn until the 5-minute idle timeout expires.

What steps can reproduce the bug?

Switch vpn, turn wifi on/off/put laptop to sleep and resume.

What is the expected behavior?

Codex should detect dead websocket connections promptly after network changes and either:

  • reconnect within seconds, or
  • clearly show a reconnecting / waiting-for-network state instead of Working

Additional information

Any of these would be an improvement:

  • add proactive websocket heartbeat ping/pong from the client and fail the connection if pong is not received within a short deadline
  • lower the effective websocket idle detection timeout during active turns
  • surface the first websocket reconnect attempt in the TUI instead of hiding it in release builds
  • distinguish between “model is working” and “connection is stalled / reconnecting”

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 4 months ago

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

  • #15489
  • #16096
  • #15841
  • #15325

Powered by Codex Action

Ragnoroct · 1 month ago

I traced my Linux suspend/resume stalls to IPv6 address rotation.

After resume, NetworkManager has removed the WebSocket's source address, but
Linux still reports the TCP socket as established (SO_ERROR=0, no EOF). Codex
reuses it and waits for the 300-second timeout.

Ragnoroct/codex@082a5fc is a diagnostic-only commit. It checks the socket's local IP before each send with a temporary UDP bind (no traffic):

before suspend: assigned
after resume:   stale (EADDRNOTAVAIL)