teachyou.ai academy
← All posts
Codex

OpenAI Codex Common Errors and Troubleshooting

Pramod Dutta · May 16, 2026 · 14 min read

Why Codex Breaks in Ways That Feel Different From Other CLIs

If you've moved from a browser-based coding assistant to the OpenAI Codex CLI, the first week usually goes one of two ways. Either it feels magical because it can read your repo, run your tests, and patch files without you copy-pasting anything — or it grinds to a halt on an error message that gives you almost no useful information. Usually it's both, in the same afternoon.

Codex CLI is fundamentally different from a chat window. It runs a real process on your machine, inside a sandbox, with a config file, an approval policy, and (optionally) a fleet of Model Context Protocol servers it can call out to. That means the failure modes aren't just "the model said something wrong." They're process failures: permission denials, config parsing errors, network timeouts, git worktree conflicts, and version mismatches between the CLI and the API it's talking to.

This guide walks through the errors people actually hit — the exact messages, the root causes, and the fixes — organized by the part of the system that's failing. We'll cover authentication, sandboxing and approvals, configuration files, MCP server issues, git and diff application failures, context/token limits, and network/rate-limit problems. If you're debugging Codex right now, jump to the section that matches your error. If you're setting it up for the first time, read straight through — it'll save you the debugging later.

Authentication and Login Failures

The single most common category of Codex problems has nothing to do with code generation — it's getting logged in and staying logged in.

"Not logged in" or repeated login prompts. Codex CLI supports two auth modes: signing in with your ChatGPT account (which uses your Plus/Pro/Team subscription quota) or using an API key billed per token. A very common mistake is having both configured inconsistently — an API key in the environment while you've also run codex login with a ChatGPT account. Codex will pick one, and if it's not the one you expect, you'll see usage against the wrong quota or an auth error when the token from the other path has expired.

Fix: check which credential is actually active.

codex login status

If it shows a stale ChatGPT session, log out and back in cleanly:

codex logout
codex login

If you intend to use an API key instead of ChatGPT auth, make sure OPENAI_API_KEY is set in the shell that launches Codex, not just in a .env file that nothing is sourcing:

export OPENAI_API_KEY="sk-...."
echo $OPENAI_API_KEY

A subtle variant of this bug: the environment variable is set in ~/.zshrc, but you launched your terminal (or your IDE's integrated terminal) before that file was sourced, or you're running Codex from a script executed by cron or a CI runner that doesn't load your shell profile at all. If Codex works in an interactive terminal but fails identically in a script, this mismatch is almost always the cause.

"Failed to refresh token" or the browser auth loop never completes. codex login opens a browser tab for the OAuth flow. On headless machines (remote servers, containers, SSH sessions without X forwarding) that browser can't open, and Codex will hang or print a URL that never gets visited. Two fixes:

  • Copy the printed URL manually into a browser on your local machine, complete the flow, and paste the resulting code back if the CLI prompts for it.
  • On genuinely headless environments, skip ChatGPT login entirely and authenticate with an API key instead — it avoids the browser round trip completely.

401 / 403 errors mid-session after working fine for days. This is almost always an expired or revoked API key, or a ChatGPT session that got invalidated because you changed your password or revoked sessions elsewhere. Re-run codex login (or rotate the key in your OpenAI dashboard and re-export it) rather than assuming it's a Codex bug.

Sandbox and Approval Errors

Codex CLI runs model-suggested commands inside a sandbox by default, and this is where a lot of first-time confusion comes from — the model can "know" the right command but still fail to execute it.

Command fails with a permission/sandbox denial even though it looks like a normal shell command. Codex's default sandbox modes restrict filesystem writes outside the working directory and block network access unless you've explicitly allowed it. A command like this will get denied under the default workspace-write policy:

curl -s https://registry.npmjs.org/left-pad | jq .

because outbound network access is off by default in the sandbox, even though the sandbox otherwise allows writing files in your project directory. The fix depends on intent:

  • If you trust the specific command, approve it when prompted (or re-run with a broader approval flag for that one invocation).
  • If you're going to need network access regularly for this project (installing packages, hitting an internal API during dev), configure it explicitly rather than approving every single call:
# ~/.codex/config.toml
[sandbox_workspace_write]
network_access = true
  • If you want to skip sandboxing for a one-off trusted task (only do this in a disposable environment or a container you don't mind Codex having full access to):
codex --dangerously-bypass-approvals-and-sandbox "run the full test suite and fix failures"

That flag name is intentionally scary — it disables both the approval prompts and the sandbox, so anything the model decides to run, runs unguarded. Reserve it for containers you'd be fine wiping.

"Operation not permitted" writing to a file that looks like it's inside your project. This shows up when your working directory is a symlink, or when the project spans a mount point that the sandbox's path-scoping doesn't resolve the way you'd expect. Check where you actually launched Codex from:

pwd -P

-P resolves symlinks to the real path. If the resolved path differs from what you expected, that's your answer — launch Codex from the canonical path, or adjust the writable roots in your config:

[sandbox_workspace_write]
writable_roots = ["/Users/you/projects/real-repo-path"]

Approval prompts appearing for every single file edit, making the session unusable. This means you're on the strictest approval policy (untrusted or the default conservative setting) for a task that's clearly repetitive and low-risk, like a big refactor across many files. Switch the approval policy for the session rather than clicking through fifty prompts:

codex --ask-for-approval on-failure "rename all instances of getUserData to fetchUserProfile across the src/ directory"

on-failure only interrupts you when a command actually errors, which is a reasonable middle ground between full auto-pilot and approving every write.

Configuration File Errors (config.toml)

Codex reads ~/.codex/config.toml (and an optional project-level config) for defaults — model choice, approval policy, sandbox settings, MCP server definitions. Malformed TOML is a frequent, entirely avoidable source of crashes.

Codex exits immediately with a parse error before doing anything. A typical message looks like:

Error: failed to parse config file at /Users/you/.codex/config.toml: invalid TOML value at line 14

The most common causes are copy-pasted snippets from documentation or blog posts that don't quite match your existing file structure — usually a duplicated table header, or a string value missing its closing quote. Validate the file directly instead of guessing:

python3 -c "import tomllib; tomllib.load(open('/Users/you/.codex/config.toml','rb'))"

If that raises an exception, it will point you to roughly the right line. Common mistakes to check for:

# Wrong: duplicate table, second one silently overrides or errors depending on parser
[model]
name = "gpt-5-codex"

[model]
reasoning_effort = "high"

# Right: one table, all keys inside it
[model]
name = "gpt-5-codex"
reasoning_effort = "high"
# Wrong: unquoted string value
approval_policy = on-failure

# Right
approval_policy = "on-failure"

A setting you added seems to be ignored. Codex merges a project-level .codex/config.toml (if present in the repo) with your user-level ~/.codex/config.toml, and depending on version and key, one can shadow the other. If you set something globally but it doesn't seem to apply inside a specific repo, check for a local override:

find . -maxdepth 3 -iname "config.toml" -path "*codex*"

If a project-local config exists and doesn't set the key you care about, that's fine — but if it exists and *does* set it to something else, that's your answer.

Profile selected with `--profile` doesn't seem to exist. Profiles are named sub-tables under [profiles.name]. If you reference a profile that doesn't match exactly (case-sensitive, no typo tolerance), Codex will either fall back silently to defaults or error depending on version — always double check the exact key:

[profiles.reviewer]
model = "gpt-5-codex"
approval_policy = "untrusted"
codex --profile reviewer "review this PR diff for security issues"

MCP Server Connection Failures

If you've wired up Model Context Protocol servers (filesystem tools, a database connector, a browser automation server) Codex needs to spawn and talk to each one at startup, and this is a rich source of errors because you're now debugging two processes instead of one.

Codex hangs on startup with no output, then eventually times out. This is almost always an MCP server that's blocking on stdin/stdout in a way that never resolves, or a server binary that isn't actually executable from the path you gave it. Test the server command in isolation first, outside Codex entirely:

npx -y @modelcontextprotocol/server-filesystem /Users/you/projects

If that command itself hangs or errors, the problem is the MCP server, not Codex. If it runs fine standalone but fails under Codex, check your config entry for the command and args split correctly:

[mcp_servers.filesystem]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/projects"]

A common mistake is putting the whole command as one string in command instead of splitting the binary from its arguments — TOML won't error on this, but the spawn call will fail because there's no executable literally named npx -y @modelcontextprotocol/server-filesystem.

"MCP server exited with code 1" during a session. Check what that server logs to stderr — most MCP servers print a real error before dying (missing API key, wrong Node version, port already in use). Run it manually with the exact same environment variables Codex would give it:

env | grep -i API_KEY
npx -y @modelcontextprotocol/server-github

If it needs an env var that's only set in your interactive shell and not exported to child processes, add it explicitly to the server's config block:

[mcp_servers.github]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
env = { GITHUB_PERSONAL_ACCESS_TOKEN = "ghp_xxx" }

Tools from an MCP server never show up even though the server connects. Some servers need an initialization handshake or a specific protocol version. If the server logs show a successful connection but Codex's tool list doesn't include anything from it, check the server's own logs for a schema validation failure — this usually means the server is built against an older or newer MCP spec version than your Codex CLI supports. Upgrading either the server package or the Codex CLI to matching current versions resolves this in most cases:

npm view @modelcontextprotocol/server-filesystem version
codex --version

Git, Diffs, and Patch Application Failures

Codex frequently proposes changes as patches, and applying them cleanly depends on the state of your working tree matching what the model saw.

"Failed to apply patch" or a patch that partially applies, leaving files in a broken state. This happens when the file changed between when Codex read it and when it tried to write the patch — for example, you edited the file yourself in another window mid-session, or a linter/formatter's pre-save hook rewrote it. Check git status immediately:

git status
git diff

If a patch is half-applied, don't try to have Codex "fix" the broken file blind — that compounds the problem. Reset the specific file to its last known-good state and ask Codex to regenerate the change against the current content:

git checkout -- path/to/broken_file.py

Then re-run the same instruction. Codex re-reads the file fresh and generates a patch against the real current state.

Codex says it edited a file but `git diff` shows nothing. Two likely causes. First, the file is covered by .gitignore, so git isn't tracking changes to it at all — verify with:

git check-ignore -v path/to/file

Second, you're in a different git worktree or branch than you think you are, especially if you've been using git worktree add for parallel Codex sessions on different branches. Confirm your actual location:

git rev-parse --show-toplevel
git branch --show-current

Merge conflicts appearing after Codex commits, when you had a clean tree beforehand. If you're running Codex in parallel across multiple worktrees pointed at the same underlying repo, two sessions touching overlapping files will eventually collide. This isn't a Codex bug — it's the same conflict you'd get from two human collaborators editing the same lines. Keep parallel Codex sessions on genuinely separate files or modules, or serialize the work.

Context Length and Token Limit Errors

"This model's maximum context length is X tokens" or the session suddenly gets much dumber on a large repo. Codex has to fit your instructions, relevant file contents, and conversation history into the model's context window. On large monorepos, if you ask a broad question ("refactor the auth module") without narrowing scope, Codex may try to pull in more files than fit, and either truncate silently (leading to worse answers) or hit a hard context error.

Fix by being explicit about scope instead of relying on Codex to guess what's relevant:

codex "refactor src/auth/session.py and src/auth/tokens.py only — do not touch src/auth/legacy/"

Session becomes slow and error-prone after a long-running conversation. Long sessions accumulate context — every prior turn, every file Codex read, every command output. If you've been in one Codex session for hours across many unrelated tasks, start a fresh session for the next unrelated task rather than continuing the same thread indefinitely:

codex resume --list

lets you see and pick up prior sessions instead of always piling more onto the current one, and starting clean for a new feature area avoids dragging irrelevant history (and irrelevant token cost) into every new request.

Rate Limits, Network Errors, and Timeouts

"429 Too Many Requests" or "rate_limit_exceeded" mid-task. If you're on the API-key billing path, this means you've hit your organization's requests-per-minute or tokens-per-minute cap, which is common when Codex is making several tool calls in quick succession (read a file, run a test, read the output, propose a fix — each is a round trip). Check your usage against your tier's limits in the OpenAI dashboard. If you're consistently hitting it during normal work, either request a rate limit increase or reduce concurrency if you're running multiple Codex sessions in parallel against the same API key.

Requests failing with connection timeouts on a stable network. This is sometimes a corporate proxy or VPN intercepting outbound HTTPS in a way that breaks streaming responses. Test basic connectivity to the API directly:

curl -v https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY"

If that hangs or fails with a TLS error but works fine when you disable your VPN, you've found the culprit — you'll need to either allowlist the OpenAI API domains in your corporate proxy config or run Codex from a network path that bypasses it.

Intermittent "stream ended unexpectedly" during long-running responses. This is usually a flaky network layer dropping a long-lived HTTP connection (a corporate firewall, a laptop switching Wi-Fi networks mid-response) rather than a Codex bug. If it happens repeatedly on the same task, break the task into smaller steps so each individual model turn is shorter and less exposed to a mid-stream drop.

A Practical Debugging Checklist

When something breaks and the error message isn't self-explanatory, work through these in order before assuming it's a deep bug:

  1. Check codex --version and confirm you're not several versions behind — a surprising number of "weird" errors are fixed in a point release.
  2. Reproduce the failing command in isolation, outside Codex, if it involves an external tool (an MCP server, a CLI Codex is shelling out to, a network call).
  3. Check git status and git diff before and after any Codex-driven change so you always know exactly what moved.
  4. Validate config.toml with a TOML parser rather than eyeballing it.
  5. Narrow scope explicitly in your prompt when working in a large repo — don't make Codex guess what files matter.
  6. Separate "auth problems" from "everything else" first — codex login status takes five seconds and rules out an entire category of confusing downstream errors.

Most Codex failures are boring once you find the layer they're actually happening in — sandbox policy, config syntax, an MCP subprocess, or a stale credential. The trap is debugging the symptom (a weird patch failure, a strange refusal) as if it's a model reasoning problem, when it's actually a plumbing issue one level down.

If you want a structured, hands-on path through setting Codex up correctly the first time — sandbox modes, approval policies, MCP integration, and the debugging habits that prevent most of these errors from happening in the first place — our OpenAI Codex CLI Tutorial course on teachyou.ai walks through it step by step with real projects, not just documentation summaries.