Codex Is Slow While ChatGPT on the Web Works? Troubleshoot Proxies, Reconnects, and TLS Errors
ChatGPT on the web responds normally and Google is fast, but Codex takes a long time to respond or repeatedly shows Reconnecting. When that happens, check Codex's connection errors first, then decide whether to change the route, adjust the proxy, or wait for the model.
A working website proves only that the browser's current route works. It does not prove that Codex requests use the same proxy or that Codex's persistent connection is healthy. If the logs already show tls handshake eof, a connection reset, or repeated reconnects, the wait cannot all be attributed to model inference.
This article covers Codex delays accompanied by connection errors. The troubleshooting order is: determine whether it is reconnecting → confirm the actual proxy route → check TLS and ordinary HTTPS → then test WebSocket or streaming connections.
The findings below use one experiment on a Mac: three real Codex calls completed over Tailscale; a saved AnyTLS node produced TLS EOFs in an isolated rebuild and even failed to reach Google over HTTPS. This did not fully reproduce the earlier state of “the website is fast, only Codex is slow,” so it cannot be treated as the sole root cause of that historical issue. It helps identify which layer to check first when different evidence appears.
Is Codex thinking, or is it reconnecting continuously?
Find the error associated with the current request first. Do not judge only by how long the interface has been waiting.
| What you see | What to check first |
|---|---|
Reconnecting... together with tls handshake eof |
Proxy route, TLS connection setup, and forwarding to the destination |
stream disconnected before completion |
Inspect the specific error that follows; this message alone does not identify the cause |
| WebSocket disconnects after connecting, close code 1006 | The connection's close time and duration, and the intermediary network path |
| HTTP 400 explicitly says the model requires a newer version | Client version; do not initially classify it as a network problem |
| No connection error, just a long wait for a result | Keep the cause open; slowness alone does not establish a network disconnect |
For this run, the same model and reasoning level were used, with a request for Codex to return the fixed text NETWORK_PROBE_OK:
| Route | Real-call result |
|---|---|
| Tailscale, three independent short sessions | All completed; the full CLI process took 11.551, 13.945, and 14.877 seconds |
| Local HTTP CONNECT, egress over Tailscale | Completed; the full process took 11.634 seconds |
| Local HTTP CONNECT, using the saved AnyTLS node | Reconnected repeatedly; did not complete during the 45-second observation window |
The failed call produced these logs:
Reconnecting... 2/5 (... tls handshake eof)
Reconnecting... 3/5 (... tls handshake eof)
Reconnecting... 4/5 (... tls handshake eof)
Reconnecting... 5/5 (... tls handshake eof)
Reconnecting... waiting for network
In this situation, continuing to wait does not mean the model is steadily generating an answer. The request is failing to connect and retrying, so investigate the connection first.
The times in the table include process startup, authentication, inference, and transfer. They are not time to first token or pure network time. The 45 seconds is the test program's termination limit, not the proxy's average response time.
Why can ChatGPT on the web work while Codex cannot connect?
Check the actual connection used by the browser, desktop app, and CLI separately. Browser proxy extensions, system proxies, TUN, per-process routing, and terminal proxy environment variables may cover different traffic. One program working does not prove another uses the same route.
With Clash Verge, check these three things first:
- Does the Clash connection log show the corresponding traffic when Codex sends its request? Setting a variable in the terminal does not verify that the request actually passed through the proxy.
- Did the request match the expected rule and exit route? Check the current request, not only the node-selection screen.
- Are you comparing the same client context? A working CLI test does not prove that every desktop background connection works; a responsive website cannot stand in for a desktop connection test either.
In this run's real CLI proxy test, the isolated proxy's connection log showed chatgpt.com, confirming that the request entered that proxy. A separate HTTP CONNECT positive control completed a real request, showing that this client could work through that entry point during this run.
However, the durable/app-server channel that reported errors in the desktop logs needs separate analysis. OpenAI's documentation also lists SSE, WebSocket requests, and events as distinct telemetry categories, so success and failure across different channels cannot be combined into a single conclusion that “Codex networking is fine.” Codex connection telemetry event categories
If the browser works but the corresponding Codex traffic does not appear in the expected proxy, correct that request's route first. Repeatedly changing nodes may not change the connection that is failing.
What should you check first when Codex reports tls handshake eof?
tls handshake eof points to an early end during the TLS handshake. It does not mean “the WebSocket connected normally and later timed out while idle.” First check whether ordinary HTTPS works through the same proxy, then investigate the application's persistent connection.
Check whether ordinary HTTPS works through the same proxy
Use a simple HTTPS address, once through the current system network and once through an explicitly specified local proxy. Use the port of the client that is actually running. Testing the same URL only in a browser still cannot confirm the route Codex uses.
The commands below use a replaceable example port. 7897 is only an example: change it to your current Clash HTTP or mixed port. This experiment used a temporary port assigned by its script.
# 不显式使用 HTTP 代理,沿当前系统路由访问。
# 如果开着 TUN 或 Tailscale,这不等于绕过它们。
curl --noproxy '*' --connect-timeout 10 --max-time 25 \
-o /dev/null -sS -w 'HTTP=%{http_code} total=%{time_total}s\n' \
https://www.google.com/generate_204
# 明确经过本地 HTTP/mixed 代理入口。
curl --proxy http://127.0.0.1:7897 --noproxy '' \
--connect-timeout 10 --max-time 25 \
-o /dev/null -sS -w 'HTTP=%{http_code} total=%{time_total}s\n' \
https://www.google.com/generate_204
If the local port cannot be reached, first confirm Clash is running and the port is correct; you have not tested the remote node yet. If it fails only at the TLS stage, inspect the node and destination forwarding. If both commands succeed, that shows only that short HTTPS works; continue by testing Codex.
This run tested each destination on each route three times:
| Test destination | Tailscale route | Isolated proxy route through saved node |
|---|---|---|
Google generate_204 |
HTTP 204 all three times | curl 35 all three times, with no HTTP response |
| ChatGPT homepage | HTTP 403 all three times | curl 35 all three times, with no HTTP response |
| Unauthenticated GET to the Codex responses address | HTTP 405 all three times | curl 35 all three times, with no HTTP response |
curl 35 is an SSL/TLS connection error; the message in this run was SSL_ERROR_SYSCALL. curl error code reference
The 403 and 405 do not mean ChatGPT or Codex features work; they mean only that the probe received an HTTP response. An unauthenticated GET is even less a substitute for a legitimate model call. The actual application check is the request returning the fixed marker in the previous section.
Still, because the proxy route also failed to reach Google over HTTPS, the troubleshooting order should change: restore general HTTPS forwarding first instead of immediately treating Codex's WebSocket as the cause.
A reachable node does not mean it can connect to OpenAI for you
If the proxy entry point is reachable, also check authentication, protocol compatibility, and forwarding to the destination.
For this run, the proxy client was bypassed and native sockets were bound to the physical network interface to connect to the four IPv4 addresses resolved for the node. TCP connections to all four addresses succeeded in about 4–7 ms; TLS handshakes with certificate verification also succeeded, taking about 248–553 ms overall.
That establishes only that the entry point is reachable. The proxy path has further steps:
本机 → 代理入口 TCP/TLS → 认证、协议处理与转发 → 目标服务
Successful TLS to the entry point and successful TLS to a destination through the proxy are two different checks. The first does not prove AnyTLS authentication succeeds or that the node can reach Google or OpenAI.
In this run, pinning the node hostname to one resolved IP still did not make Google HTTPS work. The local HTTP CONNECT entry point, when switched to DIRECT and routed out over Tailscale, returned Google 204 instead. These controls shift attention toward node-protocol/client compatibility, authentication and forwarding state, and server-side egress logs, but they do not establish one unique root cause.
If your result is similar, the next step is to obtain error records from those stages rather than ending the investigation with “ping is low” or “the server port is reachable.”
Codex keeps reconnecting. Should you disable WebSocket?
First distinguish two things: the WebSocket used by the Codex app and the transport protocol used by a proxy node.
The saved selected node in this run was AnyTLS, not a VLESS/WS node from the configuration. So the guess that “this node is slow because it wraps traffic in WS” does not match the saved node type. Codex's own WebSocket could still fail while passing through it.
Whether to investigate WebSocket depends on how far the connection got:
| Evidence so far | What to investigate |
|---|---|
| Ordinary HTTPS cannot complete a TLS handshake either | Fix proxy connection setup and forwarding first |
| Ordinary HTTPS works, but the WS handshake fails | Check that connection's handshake, proxy route, and access policy |
| WS connects, then disconnects during use or after idle time | Record when it disconnects; inspect keepalive behavior and the intermediary path |
This run checked a persistent connection with Postman's public WSS Echo service: over Tailscale, five messages were exchanged, the test client's active periodic ping was disabled, the connection sat idle for 90 seconds, and then five more messages were exchanged. All ten echoes matched. Disabling active pings does not mean TCP keepalive or frames sent by the server were eliminated. Postman Echo service notes
A separate HTTP CONNECT/DIRECT positive control also completed the WSS handshake and echo. It shows that this local proxy entry can carry WSS; it does not generalize to every proxy node. A public Echo service is not a substitute for testing Codex's specific endpoint either.
The historical desktop logs contained 10 websocket_error events and 15 reconnect_started events involving the durable channel. These are event records, not 25 independent failures; one error may also propagate into several state logs.
Close code 1006 means an abnormal closure. By itself, it cannot tell you who interrupted the connection. RFC definition of the WebSocket abnormal closure code
So do not apply a “disable WS” setting automatically when Reconnecting appears. In this run, failures occurred as early as the TLS stage, and there is not yet evidence that changing the WebSocket idle timeout would address them.
Can switching to Tailscale fix Codex delays?
For this Mac's short-request tests, Tailscale was a route that completed real calls; that is not a general promise that it will be faster. Three real Codex calls and a 90-second idle echo provide more useful evidence for the current choice than a speed test alone.
Tailscale uses WireGuard. When it can connect directly, it transports traffic over UDP; when it cannot, it may use a relay. Codex's WebSocket can run inside its tunnel; switching to Tailscale does not disable WebSocket. How Tailscale connections work
Of 20 Tailscale discovery probes in this run, 17 succeeded and three timed out. The median RTT among successful samples was 188 ms. This is not a long-term packet-loss rate for application traffic, but it also shows that “works” does not mean “zero latency and no anomalies.”
Likewise, dig cannot prove congestion on the 163 backbone. All three A-record queries for the ChatGPT domain succeeded in this run, taking 185–233 ms. Those measure DNS lookup time, not TCP, TLS, or actual application requests. This run did not obtain path evidence sufficient to confirm 163 backbone congestion.
If Codex recovers after changing the egress route, what you can establish is that “changing the route changed the result.” Attributing it further to a specific carrier, shared-node load, or proxy protocol needs evidence that supports that claim.
How can you confirm Codex recovered, instead of just seeing the website open?
Test in the client where the issue occurred; do not only return to the browser and refresh the homepage.
- Send a short request that does not call tools. Keep the same model and reasoning level, and confirm that a complete result arrives. This avoids mixing tool execution time into a connection check.
- Confirm the matching request's proxy rule, egress, and error logs. Check whether reconnects continue; setting a proxy does not prove the request passed through it.
- Test the workflow that originally failed. A short request does not replace checking a long task, recovery after idle time, or desktop background channels. This run completed only short model requests; it did not prove that long workflows had recovered.
In the desktop app, send: “Do not read files or call tools; reply only with NETWORK_PROBE_OK.” CLI users can use this short-request example. It makes a real model call; it is not an offline check:
codex exec --ephemeral --skip-git-repo-check --sandbox read-only \
'不要读取文件或调用工具,只回复 NETWORK_PROBE_OK'
Verify using the version and settings that actually had the problem, and record the errors and completion status. Do not declare the desktop app recovered because a different CLI can answer.
If the client explicitly says the model requires a newer version, resolve version compatibility first. The first test in this run encountered exactly that: standalone CLI 0.151.0 returned HTTP 400; it was then retested using the app-bundled 0.164.0-alpha.11.1. The earlier response was not counted as a network failure.
Given these results, the practical choice is to continue using Tailscale, which completed real calls, and, when investigating this proxy, restore ordinary HTTPS before testing Codex's specific connection. To explain the earlier issue where the website worked but only Codex was slow, connection and egress logs still need to be collected while that condition is reproduced.
Test scope: The data in this article comes from tests on a Mac in the early hours of October 27, 2026. The proxy experiment read saved AnyTLS node parameters and rebuilt them in a separate mihomo process. It did not start the original Clash GUI/TUN, switch the system proxy, or change the Tailscale egress route. Although physical-interface binding was configured, nettop did not capture a verifiable upstream interface for the AnyTLS process, so the two complete physical routes cannot be claimed as fully independently verified. CLI, desktop durable-channel, and public Echo results were recorded separately. Raw data, scripts, and detailed conditions are in the accompanying experiment materials.
Author:AIRouter
Link:https://www.airouter.me/blog/codex-slow-chatgpt-works
Non-commercial reuse with attribution (CC BY-NC-SA 4.0).