Stale proxy in $CODEX_HOME/.env causes misleading macOS `os error 61`; clean home works
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.5k
- PR merge metrics
- PR metrics pending
Description
Confirmed root cause
This was ultimately caused by a stale proxy configuration in $CODEX_HOME/.env (default: ~/.codex/.env), not by Clash Verge Rev, DNS, TUN/Fake-IP, the proxy node, ChatGPT Plus authentication, database corruption, or a Codex binary regression.
The affected .env was only 135 bytes and defined:
HTTP_PROXYHTTPS_PROXYALL_PROXYNO_PROXY
The first three variables pointed to a loopback proxy on 127.0.0.1:7890. Nothing was listening on that port anymore. Codex therefore attempted to reach OpenAI through a dead local proxy and surfaced only the destination URL:
failed to connect to websocket: IO error: Connection refused (os error 61),
url: wss://chatgpt.com/backend-api/codex/responses
Falling back from WebSockets to HTTPS transport.
stream disconnected before completion: Connection refused (os error 61)
This was misleading because it looked like an OpenAI, WebSocket, VPN, DNS, or routing failure. The actual refused connection was the hidden local proxy hop.
Minimal causal reproduction
All tests used the same Mac, account, authentication, network, proxy node, application bundle, and bundled Codex binary (0.148.0-alpha.9).
- Start with a clean recovery
CODEX_HOME: the request returnsOK. - Copy only the old
.envinto that working home. Do not copy any chat, database, config, cache, or runtime file. - Run:
CODEX_HOME="/path/to/recovery-home" \
/Applications/ChatGPT.app/Contents/Resources/codex \
exec --skip-git-repo-check "Reply with exactly: OK"
- The exact original failure is reproduced: WebSocket
Connection refused (os error 61), followed by failed HTTPS fallback. - Move the
.envout of the recovery home. - Run the identical command again: it immediately returns
OK.
This establishes file-level causality. All discovered SQLite databases also passed integrity_check.
Resolution
Before deleting or replacing the entire Codex state directory:
- Fully quit the ChatGPT/Codex desktop app.
- Determine the active home:
CODEX_HOME_DIR="${CODEX_HOME:-$HOME/.codex}"
- Check whether
$CODEX_HOME_DIR/.envexists. - Inspect only the proxy-related keys locally. Do not paste the complete file into an issue or AI chat because proxy URLs can contain credentials.
- For every loopback proxy address found, verify that the port is actually listening:
lsof -nP -iTCP:7890 -sTCP:LISTEN
- Back up the file, then remove or correct only the stale proxy configuration.
- Relaunch Codex and test with the bundled CLI.
In this case, excluding the stale .env restored the current desktop app and bundled CLI without changing Clash, DNS, TUN, the OpenAI account, or the application version.
First checks for AI troubleshooting agents
If a user reports any of the following:
error sending requestConnection refused (os error 61)- repeated
Reconnecting... waiting for network - WebSocket failure followed by HTTPS fallback failure
- browser/curl works but Codex does not
Do these checks before recommending reinstalling the app, changing DNS, disabling TUN, switching proxy clients, rotating nodes, logging out, or deleting ~/.codex:
- Inspect
$CODEX_HOME/.env(default~/.codex/.env). - Enumerate
HTTP_PROXY,HTTPS_PROXY,ALL_PROXY,NO_PROXYand lowercase equivalents without exposing credentials. - Check whether every referenced
127.0.0.1/loopback proxy port has a listening process. - Also inspect process/launch environment and macOS system proxy settings, but do not assume they are the only proxy sources.
- A/B test the same Codex binary with:
- the affected
CODEX_HOME - a clean temporary
CODEX_HOME
- the affected
- If the clean home works, compare small environment/config/runtime files before touching session databases.
- Never advise deleting
~/.codexwithout first making a complete backup; it contains local chats, projects, session indexes, and related state.
The highest-value first question is:
Does
$CODEX_HOME/.envdefine a proxy, and is that local proxy port actually listening?
Recovering chats and projects safely
The clean-home test made old chats/projects disappear from the sidebar, but they were not deleted. They remained in the backed-up Codex home.
The durable data was found in:
sessions/**/*.jsonlarchived_sessions/*.jsonlsession_index.jsonlstate_5.sqlitethread_history_1.sqlitesqlite/codex-dev.db.codex-global-state.jsonhistory.jsonlmemories_1.sqliteandmemories/
A recovery lab was built from a known-good home, then user-data groups were migrated without the stale .env, old auth/config, locks, sockets, logs, caches, WAL/SHM sidecars, shell snapshots, or process-manager state.
Validated recovery result:
- 174/174 old session files recovered and parsed
- 103 active sessions
- 71 archived sessions
- 174 old thread records
- 11 projects
- 19 thread-to-project associations
- all active SQLite databases:
integrity_check=ok - the bundled
0.148.0-alpha.9still returnedOKafter every recovery group
For most affected users, simply backing up and removing/correcting the stale .env in the original home should preserve all chats and projects. The selective migration was used here only because a clean home had already been installed during troubleshooting.
Environment
- ChatGPT/Codex Desktop:
26.810.41047(build6570) - Bundle ID:
com.openai.codex - Bundled Codex CLI:
0.148.0-alpha.9 - Subscription: ChatGPT Plus
- Platform: macOS, Apple Silicon (
arm64) - Proxy client: Clash Verge Rev
Why the earlier diagnostics were misleading
The affected network path itself was healthy:
- Clash Verge Rev TUN + Global mode was working.
chatgpt.comresolved into the Fake-IP range and routed through the TUN interface.- TLS reached
chatgpt.com. GET /backend-api/codex/responsesreached OpenAI and returned the expected405 Method Not Allowedwithallow: POST.- Stable Codex
0.144.4worked with a clean home. - The bundled
0.148.0-alpha.9also worked with that same clean home. - Removing only
config.tomldid not help.
Those results correctly pointed to persistent state outside config.toml, but the error message did not reveal the effective proxy source or the refused local proxy address.
Requested product improvements
- Include the effective proxy target (with credentials redacted) in transport diagnostics.
- Identify the source of the proxy setting, such as process environment vs.
$CODEX_HOME/.env. - When a loopback proxy returns
ECONNREFUSED, show an actionable message such as:
Local proxy 127.0.0.1:7890 is not listening; check $CODEX_HOME/.env. - Add a diagnostics command/page that reports effective network configuration safely.
- Avoid presenting a failed local proxy hop only as an error for the final
chatgpt.comURL.
A 135-byte stale .env caused hours of unnecessary investigation across DNS, TUN, WebSockets, versions, authentication, nodes, and reinstall attempts. Surfacing the effective proxy would make this failure immediately actionable.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the failure with the bundled CLI and compare the affected CODEX_HOME against a clean temporary home, focusing on .env proxy variables and the loopback port. Done means transport diagnostics safely report the effective proxy target and source, and identify an unlistening local proxy instead of showing only the final chatgpt.com URL.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli, networking, observability
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100