Claude Code exit codes
What each Bash tool exit code means in Claude Code — including 126, which doesn't mean what it usually does, and the Windows bug behind most exit code 1s.
When Claude Code's Bash tool fails, it reports the shell's exit code. Most of those codes carry their standard Unix meaning — but one of them doesn't, and that one causes the most confusion.
Quick reference#
| Code | Standard meaning | In Claude Code |
|---|---|---|
| 1 | Generic failure | Often a Windows shell-resolution bug, not your command — below |
| 2 | Misuse of a shell builtin | Same; usually a real syntax error |
| 126 | Command found but not executable | ⚠️ Also a deliberate security block — below |
| 127 | Command not found | Same; a PATH problem — below |
| 137 | 128 + 9 → killed by SIGKILL | Usually out-of-memory, or an interrupt — below |
| 143 | 128 + 15 → terminated by SIGTERM | A graceful stop: timeout or cancellation |
| 130 | 128 + 2 → SIGINT | Ctrl-C |
Anything above 128 is 128 + signal number. That arithmetic is the whole trick: 137 - 128 = 9 (SIGKILL), 143 - 128 = 15 (SIGTERM). If you see an unfamiliar code above 128, subtract 128 and look up the signal.
Exit code 126: the one that differs#
Everywhere else in Unix, 126 means the file exists but isn't executable. In Claude Code it is also used for a deliberate security refusal:
Error: Exit code 126 [BLOCKED — DO NOT RETRY]
Command uses eval or $()/backticks at command position, which is blocked
regardless of allowlist. This is a permanent security restriction, not a
transient error.Read the message rather than the number. "Permanent security restriction, not a transient error" means retrying will never work — and neither will adding the command to an allowlist, because the block sits above allowlist evaluation.
The trigger is a command substitution in command position — the shell deciding what to run based on the output of another command:
eval "$SOMETHING" # blocked
$(which python) script.py # blocked — substitution decides the binary
`which node` app.js # blocked — same thing, backticksRewrite so the binary is literal:
python script.py # fine
node app.js # fine# need the resolved path? resolve it in a separate step, then use it
which pythonIf the real problem is a genuinely non-executable file, that's the ordinary 126 and the fix is ordinary too:
chmod +x ./script.shExit code 1: usually not your command#
Exit code 1 is generic, so it's the most-reported and the least self-explanatory. The distinguishing symptom that matters: exit code 1 with no output at all, on commands that work fine when you run them yourself.
That combination points at a Claude Code bug rather than your command.
Windows: Git Bash vs WSL bash on PATH#
The best-documented cause, and a regression introduced in v2.1.45:
#26505 — the Bash tool fails silently with exit code 1 when WSL's bash is on PATH alongside Git Bash. Claude Code resolves the wrong bash.exe, and the mismatch produces no output at all. #26545 reports the same on Git Bash since the same version.
Check which bash resolves first:
where.exe bashIf C:\Windows\System32\bash.exe (the WSL stub) comes before your Git Bash path, that's your problem. Point Claude Code at the right shell explicitly:
setx CLAUDE_CODE_GIT_BASH_PATH "C:\Program Files\Git\bin\bash.exe"Open a new terminal afterwards — setx doesn't affect the session you ran it in.
Other reported exit-code-1 cases#
| Issue | Situation |
|---|---|
| #12545 | npm commands fail silently; work in a normal shell |
| #41124 | No stdout/stderr on CachyOS / Arch Linux |
| #22105 | Commands succeed but are reported as exit code 1 |
| #19663 | No output on macOS 26 |
| #12115 | Commands fail with exit code 1 and no output |
#22105 is worth singling out: the command did the work and still reported failure. If your files changed but the tool says it failed, don't let the agent "fix" it — you'll get the operation applied twice.
The diagnostic#
Run the identical command in your own terminal:
cd /your/project && the-exact-command-that-failed
echo "exit: $?"- Works in your shell, fails in Claude Code → a Claude Code bug; check the table above
- Fails in both → your command; the exit code means what it normally means
Exit code 127: command not found#
The shell couldn't find the binary. Almost always PATH, and Claude Code inherits the environment of whatever launched it — which for a GUI is often not your shell's PATH.
which the-command
echo $PATHThis is the same mechanism as 'codex' not found: a tool launched from a dock or Start menu never sourced your ~/.zshrc, so nvm, Homebrew, Volta, mise and custom npm prefixes are all invisible to it. That page has the per-OS fixes; substitute your binary name.
Exit code 137: killed#
128 + 9 — the process received SIGKILL. It didn't fail, it was killed. Two common reasons:
Out of memory. The kernel's OOM killer targets the largest process. Typical on builds, test suites, bundlers, and anything in a memory-capped container:
# Linux — did the OOM killer fire?
dmesg | tail -30 | grep -i "killed process"Docker containers hit this at their memory limit, not the host's.
An interrupt. #12153 reports claude auth commands failing with exit code 137 and [Request interrupted by user for tool use] in v2.0.50 — a regression rather than a memory problem. If you see 137 on a command that uses no memory at all, check your version:
claude --version
npm i -g @anthropic-ai/claude-code@latestExit code 143: terminated#
128 + 15 — SIGTERM, a polite request to stop. Something asked the process to exit and it complied.
Usually a timeout: the Bash tool's own limit, a CI step limit, or an orchestrator stopping the container. Unlike 137, this is an orderly shutdown, so it more often means "took too long" than "something went wrong".
For long-running commands, prefer backgrounding them and polling over letting a foreground command sit until it's killed.
Reporting one#
Include the exit code, the exact command, whether it works in your own terminal, your OS and shell, and claude --version. For exit code 1 specifically, "works in my shell, fails in Claude Code with no output" is the single most useful sentence you can write — it separates a client bug from a command error immediately.
FAQ#
What does exit code 1 mean in Claude Code?#
Generically, that the command failed. But exit code 1 with no output, on a command that works in your own terminal, usually points at a Claude Code shell-resolution bug rather than your command — most commonly on Windows when WSL's bash is on PATH ahead of Git Bash.
Why does Claude Code return exit code 126 for a command that exists?#
Because Claude Code also uses 126 for a security refusal. Commands using eval, $() or backticks in command position are blocked regardless of allowlist, and the message says "permanent security restriction, not a transient error" — retrying cannot help. Rewrite so the binary is named literally.
What is exit code 137 in Claude Code?#
128 + 9, meaning the process was killed with SIGKILL. Usually the out-of-memory killer on a build or test run, or a container hitting its memory limit. It has also been reported as a v2.0.50 regression on claude auth commands, unrelated to memory.
What is the difference between exit code 137 and 143?#
137 is SIGKILL — the process was killed outright, typically by the OOM killer. 143 is SIGTERM — it was asked to stop and shut down cleanly, typically a timeout or cancellation.
Why does Claude Code report exit code 1 when my command actually worked?#
That's a reported bug (#22105). Check whether the work was actually done before letting the agent retry — otherwise the operation gets applied twice.
How do I fix exit code 1 on Windows with Git Bash?#
Run where.exe bash and check whether WSL's C:\Windows\System32\bash.exe resolves before Git Bash. If it does, point Claude Code at the Git Bash binary explicitly and open a new terminal, since the regression in v2.1.45 comes from resolving the wrong shell.