Codex 401 in an agent shell: check credentials before blaming API key precedence
A regular terminal reported a ChatGPT login, but Codex requests inside an agent’s shell failed with:
HTTP error: 401 Unauthorized
An inherited OPENAI_API_KEY looked suspicious. The useful next step was a controlled credential-context comparison. The recorded investigation never proved that the key overrode the ChatGPT login, and it never showed a successful retry after removing it.
What the May 5 investigation established #
The installed CLI was codex-cli 0.128.0. The user reported that codex login status returned Logged in using ChatGPT before launching the agent. Inside the agent, the same status command returned Not logged in, and this request repeatedly failed:
codex exec --skip-git-repo-check "echo hello"
An early environment check found OPENAI_API_KEY present. A separate request to the OpenAI models endpoint, explicitly using that variable, returned HTTP 401. That established that the credential failed that direct probe. It did not establish which credential Codex selected.
Later checks found the variable absent, yet Codex still failed. One retry explicitly supplied an empty OPENAI_API_KEY and also received 401 responses. The chain contains no controlled env -u comparison that restored subscription access. The document-cleanup task continued with Python; Codex authentication was not shown to recover.
Calling this a confirmed case of an environment key shadowing OAuth would overstate the evidence. The login-status mismatch deserved investigation before declaring the subscription token expired or replacing it with an API key.
Compare the launch contexts without exposing secrets #
Run these checks locally in both the working terminal and the failing agent shell:
command -v codex
codex --version
codex login status
python3 - <<'PY'
import os
for name in ("HOME", "CODEX_HOME", "OPENAI_API_KEY", "CODEX_API_KEY"):
print(f"{name}: {'set' if name in os.environ else 'unset'}")
PY
Keep login-status output private if it includes credential details. The Python check prints names and presence only. Do not dump the environment, search credential files, or paste tokens into a troubleshooting conversation.
Compare the actual HOME and CODEX_HOME paths privately, too. Presence alone cannot tell you whether two processes use the same directory. Check the executable and launch configuration for differences before changing authentication.
OpenAI’s authentication documentation
distinguishes ChatGPT subscription sign-in from API-key access. It also describes credential storage in a file under CODEX_HOME or an OS credential store. A profile HOME mismatch
or unavailable credential store is a separate explanation for a missing login.
To isolate the suspected variable on a Unix-like system, keep the same executable, working directory, HOME, and CODEX_HOME, then compare:
codex login status
env -u OPENAI_API_KEY codex login status
Removing one variable affects only the second process. It does not delete the saved login or change the parent shell. If you intend to make a model request, repeat the same minimal prompt with and without that variable and compare completion and exit status. A status check alone does not prove a request will succeed. This paired request test was not completed in the May investigation.
Verification on October 31: avoid a universal precedence rule #
A separate check on 2026-10-31 used installed Codex 0.166.0 with isolated, empty HOME and CODEX_HOME directories. codex login status returned Not logged in both without a key and with a dummy OPENAI_API_KEY. No model request or real credential was used. This checks status behavior without a saved login; it does not test precedence over OAuth.
The upstream authentication loader
, inspected that day, has an environment-key precedence branch for CODEX_API_KEY, conditional on that mechanism being enabled and API-key authentication being allowed. That is not a universal rule about OPENAI_API_KEY, nor proof of what version 0.128.0 selected in May.
The earlier trusted-directory error was separate: --skip-git-repo-check bypassed that check and exposed the authentication failure. Initializing unrelated directories as Git repositories would not repair credentials.
Before logging out or deleting a working login, compare the credential context of your two launch paths and change one variable at a time.