Realtime V3 (macOS, 0.146.0-alpha.3.1): default sideband dials wss://chatgpt.com/backend-api/codex/<call_id> and is blocked by Cloudflare (cf-mitigated: challenge) → 403

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

Related to #35094, but a different sideband address and a different failure mechanism, so filing separately and cross-linking. #35094 reports the default V3 sideband as wss://api.openai.com/v1/live/<call_id> returning 404 call_id_not_found; on this build the client dials the ChatGPT backend by default and gets 403. #35094 mentions the 403 variant only as something reached by forcing the sideband path — here it is the default, unforced behaviour.

Also distinct from #18456: that one is a User-Agent–dependent Cloudflare block on reqwest clients. This one is User-Agent–independent (control table below).

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

App 26.721.41059, bundled runtime codex-cli 0.146.0-alpha.3.1 (ChatGPT.app/Contents/Resources/codex). Homebrew codex-cli 0.145.0 is also installed but is not the binary driving Voice.

What subscription do you have?

Paid ChatGPT subscription (Plus).

What platform is your computer?

macOS 25.5.0, arm64 (Apple Silicon). Cloudflare edge POP SIN.

What issue are you seeing?

Voice chat fails with:

Voice chat error: stream disconnected before completion:
failed to connect realtime websocket: HTTP error: 403 Forbidden

The WebRTC leg succeeds and the sideband WebSocket leg is refused, so audio comes up for roughly a second and then Voice tears itself down when the sideband retry loop is exhausted ~6s later.

Observed sequence, with no experimental_realtime_* overrides set and nothing forced:

POST https://chatgpt.com/backend-api/codex/realtime/calls?intent=quicksilver&architecture=avas
-> 201 Created
-> Location: /v1/realtime/calls/rtc_u0_<redacted>
-> x-codex-plan-type: plus
-> x-codex-active-limit: premium
-> x-codex-primary-used-percent: 2

INFO  codex_api::endpoint::realtime_websocket::methods
      connecting realtime websocket: wss://chatgpt.com/backend-api/codex/rtc_u0_<redacted>
WARN  realtime sideband websocket connect failed; retrying:
      stream error: failed to connect realtime websocket: HTTP error: 403 Forbidden
      attempt=1 delay_ms=218
      attempt=2 delay_ms=387
      attempt=3 delay_ms=741
      attempt=4 delay_ms=1528
WARN  codex_core::realtime_conversation
      failed to connect realtime sideband: stream disconnected before completion:
      failed to connect realtime websocket: HTTP error: 403 Forbidden
INFO  received realtime conversation event event=Error(...)
TRACE app-server event: thread/realtime/error
TRACE app-server event: thread/realtime/closed

Two things to note in that trace:

  1. The call-create response returns Location: /v1/realtime/calls/rtc_u0_..., but the sideband URL the client then dials is <base_url>/<call_id> — the /v1/realtime/calls/ prefix is dropped.
  2. The 403 is not an OpenAI application response. It is a Cloudflare bot-management challenge; the request never reaches the application (evidence below).

What steps can reproduce the bug?

  1. Sign in with ChatGPT auth (Plus) on macOS arm64.
  2. Codex Desktop 26.721.41059 with bundled runtime 0.146.0-alpha.3.1, realtime_conversation enabled.
  3. Start Voice.
  4. Call creation returns 201; the sideband WebSocket connect to wss://chatgpt.com/backend-api/codex/<call_id> returns 403 and retries 5 times.
  5. Voice closes with the error above.

What is the expected behavior?

The sideband WebSocket joins the freshly created WebRTC call and Voice stays connected.

Additional information

The 403 is a Cloudflare challenge, not an application response

Same access token, same chatgpt-account-id, same machine, same TLS client, run within minutes of a live failure:

| path under https://chatgpt.com/backend-api/codex/ | method | result |
|---|---|---|
| models?client_version=0.145.0 | GET | 200 application/json |
| realtime/calls | POST {} | 400 application/json — reaches the app |
| realtime/calls | GET | 405 application/json — reaches the app |
| rtc_u0_<test> — what the client dials | GET and WS-upgrade | 403 text/html, cf-mitigated: challenge |
| realtime/calls/rtc_u0_<test> | WS-upgrade | 403 cf-mitigated: challenge |
| v1/realtime/calls/rtc_u0_<test> | WS-upgrade | 403 cf-mitigated: challenge |
| realtime/rtc_u0_<test> | WS-upgrade | 403 cf-mitigated: challenge |
| realtime/calls/rtc_u0_<test>/sideband | WS-upgrade | 403 cf-mitigated: challenge |

Every 403 carries server: cloudflare, cf-mitigated: challenge, content-type: text/html, accept-ch: Sec-CH-UA-*, and a ~10KB interstitial HTML body.

Control 1 — not upgrade-dependent. A plain GET with no Upgrade / Connection / Sec-WebSocket-* headers is challenged identically. The mitigation keys on the path, not on the WebSocket handshake.

Control 2 — not User-Agent-dependent, which distinguishes this from #18456:

| User-Agent | models | rtc_u0_<test> |
|---|---|---|
| codex_cli_rs/0.146.0 | 200 | 403 cf-mitigated: challenge |
| Chrome 150 macOS browser UA | 200 | 403 cf-mitigated: challenge |
| (no User-Agent header) | 200 | 403 cf-mitigated: challenge |

So requests carrying the call id never reach the application. They are challenged at the edge, consistent with that path not being covered by the API route exemptions that models and realtime/calls are covered by.

Client-side network ruled out

  • No proxy — scutil --proxy has no HTTPProxy / HTTPSProxy keys, and no *_proxy environment variables are set
  • No MITM tooling running (no Proxyman / Charles / mitmproxy)
  • No VPN exit node in use; default route is the physical LAN interface and egress is the real ISP address
  • codex_ca_certificate_configured=false ssl_cert_file_configured=false, "using system root certificates" — no certificate interception
  • A network-level block would also break models and realtime/calls; both succeed

Not entitlement or quota

The call-create response is 201 with x-codex-plan-type: plus, x-codex-active-limit: premium, x-codex-primary-used-percent: 2. A genuine cap on this account on a different day produced a clearly distinct error (failed to start realtime conversation: You've hit your usage limit. Upgrade to Pro), so the two are easy to tell apart in logs.

No client-side override recovers it

experimental_realtime_ws_base_url and experimental_realtime_webrtc_call_base_url exist in the 0.146 binary, but all five candidate ChatGPT-backend path shapes in the table above are challenged, so there is no config.toml value that restores Voice on this build.

Possible relevance to #35094

If the ChatGPT-backend sideband path is edge-challenged rather than served, then api.openai.com/v1/live/<call_id> is the only sideband address that can currently reach a transceiver — and #35094 reports that one returning call_id_not_found. Both sideband addresses would then be unreachable for ChatGPT-auth sessions by two different mechanisms, which would explain why neither forcing direction produces a working call.

Log history for this account

realtime_websocket::methods connect attempts appear only from the failing session onward. Earlier Voice sessions on the same machine and account started successfully without any sideband connect being attempted, which suggests the sideband leg became active for this session/build rather than having always been on this path.

No access tokens, account ids, user ids, installation ids, real call ids, public IP addresses, or cookies are included above. Call ids in log excerpts are redacted and all probe ids are synthetic.

View original on GitHub ↗

7 Comments

github-actions[bot] contributor · 1 month ago

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

  • #35094

Powered by Codex Action

rica-cardoso · 1 month ago

I can reproduce this on another Apple Silicon Mac with the exact same Desktop/runtime combination:

  • Codex Desktop: 26.721.41059
  • Bundled runtime: codex-cli 0.146.0-alpha.3.1
  • macOS: 26.5.2
  • Cloudflare POP: GRU

The Desktop UI repeatedly closes the realtime voice overlay with:

stream disconnected before completion: realtime call response missing Location

Local diagnostics ruled out the microphone and ordinary connectivity:

  • Built-in microphone is detected, selected as the default input, and works for ChatGPT audio transcription and other applications.
  • ChatGPT has microphone permission.
  • No active VPN, system proxy, proxy environment variables, custom /etc/hosts entries, custom CA configuration, or network system extensions.
  • Default route is the physical Wi-Fi interface.

Direct unauthenticated path controls from the same machine/network produced:

  • GET /backend-api/codex/realtime/calls405 application/json with Allow: POST, so the call-creation route reaches the application.
  • GET /backend-api/codex/rtc_test_diagnostic403 text/html, cf-mitigated: challenge, served by Cloudflare at POP GRU.
  • GET https://api.openai.com/v1/live/rtc_test_diagnostic → ordinary 404, not a Cloudflare challenge.

This independently reproduces the path-specific Cloudflare mitigation described in this issue from a different edge POP. Audio transcription works because it uses a separate request flow; only continuous Codex Realtime voice fails.

No access tokens, account IDs, call IDs, public IP addresses, cookies, or attestation values are included here.

Invictus2347 · 28 days ago

Additional affected user with a ChatGPT Pro account and two independent reproductions.

Desktop reproduction

  • macOS ChatGPT desktop app 26.721.81911 (build 5973)
  • realtime_conversation feature flag is enabled
  • thread/realtime/start consistently fails with:
  • stream disconnected before completion: realtime call response missing Location
  • Surfshark VPN made no difference.
  • Tailscale is not routing ordinary internet traffic (RouteAll: false, no exit node). A controlled test with Tailscale fully stopped confirmed the Mac still reached OpenAI normally.

Patched-runtime reproduction

  • Tested the official codex-cli 0.147.0-alpha.1 runtime.
  • Confirmed commit 438c9e98db71273e4f0b63dc4a86c2db58c44706 is an ancestor of that release.
  • Confirmed the desktop app actually launched the overridden alpha executable.
  • Protocol smoke test passed, but Voice still failed with the exact same realtime call response missing Location error.

iOS reproduction

  • ChatGPT iOS Remote was connected to the same Mac and ordinary Remote task traffic worked.
  • Starting Voice over 5G cellular showed: Voice couldn’t connect — Please check your connection and try again.
  • Matching Mac logs contained no thread/realtime/start for the mobile attempt, indicating the iOS Voice failure occurred before handoff to the host.

This looks account/realtime-backend specific rather than a microphone, local installation, home-network, VPN, or Tailscale problem. Please investigate the affected account’s Voice entitlement and realtime call-creation/routing response. The feature is advertised for Pro and Remote on iOS, but it is unusable on both supported surfaces.

vimoxshah · 28 days ago

Additional reproduction on a newer macOS app/runtime

I am also affected by the Voice startup failure described in this thread. The installed versions are newer than those in the original report:

  • Codex app: 26.727.40816 (build 6067)
  • Bundled runtime used by the app: codex-cli 0.146.0-alpha.9.2
  • Standalone CLI on PATH: codex-cli 0.146.0
  • macOS: 26.5.2 (build 25F84)
  • Platform output (uname -mprs): Darwin 25.5.0 arm64 arm
  • Hardware: Apple Silicon, model Mac16,1

When starting Codex Voice, the app shows:

Voice chat couldn’t start
stream disconnected before completion: realtime call response missing Location

Expected: the Voice session starts successfully.

Actual: Voice fails during startup before the conversation begins.

This confirms that the exact realtime call response missing Location symptom persists on app 26.727.40816 with bundled runtime 0.146.0-alpha.9.2. I previously mentioned the symptom in #35474, but that issue primarily tracks a different failure mode (Connection reset by peer after 15–20 seconds), so this thread appears to be the closer match.

No account IDs, tokens, call IDs, or other secrets are included.

rica-cardoso · 19 days ago

Still reproducible — screen recording (Aug 8, 2026)

This is still failing on the same Mac/account from my Jul 27 reproduction, 13 days after this issue was opened.

The attached 15-second screen recording shows the current behavior:

  1. Start Codex Voice.
  2. The voice UI begins loading.
  3. It closes with the same error:
stream disconnected before completion: realtime call response missing Location

Regular ChatGPT microphone transcription continues to work on this Mac; only continuous Codex Voice is blocked.

This issue now has several independent confirmations, including reproductions on newer app/runtime versions, but there has not yet been a maintainer acknowledgment. Could an OpenAI maintainer please confirm whether this realtime call-creation/routing failure is being tracked and whether any additional diagnostics would help? The feature remains completely unusable for affected users.

Screen recording:

https://github.com/user-attachments/assets/4aacbae1-4333-4ca5-9f33-bf1185f76b05

chaserturbo86 · 18 days ago

Additional Windows reproduction — app 26.803.5235.0

I can reproduce the same exact Realtime WebSocket failure in Codex Desktop on Windows:

  • Codex MSIX package: OpenAI.Codex_26.803.5235.0_x64__2p2nqsd0c76g0
  • Subscription: ChatGPT Plus
  • Platform: Windows
  • Reproduced from both the normal Voice entry point and the Pets overlay
  • Reproduced repeatedly on Aug 4, Aug 5, and Aug 10, 2026
  • Voice in the mobile ChatGPT app works for the same Plus account

The local sequence shows thread/realtime/start succeeding and the realtime session starting, followed by:

Realtime voice session failed: stream disconnected before completion:
failed to connect realtime websocket: HTTP error: 403 Forbidden

Local controls:

  • Microphone permission is allowed for the packaged app
  • The configured HyperX microphone is healthy
  • Windows recorded that Codex accessed the microphone during the failed attempt
  • WinINET system proxy is Karing at 127.0.0.1:3067
  • WinHTTP reports direct access

This rules out the microphone and makes the Windows realtime WebSocket route/proxy handling the likely failure point. I cannot confirm from the available local log line alone whether this specific 403 is the same Cloudflare challenge described in the original report, but the user-visible and app-server error is identical.

In-app diagnostic feedback was submitted with ID:

019fe94c-90a5-7300-821e-0b01a1c9a0c3

Please correlate the server-side session/edge response with that feedback ID and check whether the Windows realtime sideband WebSocket honors the system proxy or is taking a different route from the rest of the app.

No raw logs, tokens, account IDs, public IPs, or browsing data are included here.

xecretary · 11 days ago

happening for me too. happening for weeks and nothing has changed. contacted support and they weren't any help.

<img width="867" height="301" alt="Image" src="https://github.com/user-attachments/assets/1dc452c4-cdf6-46c9-abc1-b75d52ef06b4" />