TechFixSignal
Claude

Claude Code PreToolUse Bash Hook Error

When Claude Code shows PreToolUse:Bash hook error after a successful exit 0 hook, emit echo {} or modern hookSpecificOutput JSON instead of silent exit.

Last checked
Sep 6, 2026
Applies to
Windows, Mac, Desktop
Fix status
Community Confirmed
Fastest useful check

Quick answer

Match the transcript label PreToolUse:Bash hook error when the Bash tool still runs. On early-exit paths that currently exit 0 with no stdout, print a no-op JSON object with echo "{}" then exit 0. If the hook returns legacy {"decision":"allow"}, switch to the modern hookSpecificOutput permissionDecision allow JSON instead. Confirm the hook still exits 0 by hand. This is a false-positive label on successful hooks, not a weekly limit and not a reason to delete every hook.

On this page

What we're seeing

  • The exact transcript label is PreToolUse:Bash hook error. Close variants include PostToolUse:Bash hook error and PostToolUse:Edit hook error.
  • Independent January and March 2026 first-hand reports on anthropics/claude-code quote that label while hooks exit 0 and still allow the tool.
  • Common triggers are silent early exit 0 with empty stdout, or legacy decision allow JSON that Claude Code still paints as an error label.
  • A real blocking failure is different: exit 2 with stderr, or a permission deny that stops the tool. Those are not this false-positive leftover.
  • Weekly limit, overloaded, and rate-limit waits are out of scope for this fingerprint.

Start here

Try these first

Fix 1

Confirm the hook error label

Community Confirmed

Match the transcript wording and whether the tool still ran before rewriting hooks.

  1. Read the transcript. This guide is for PreToolUse:Bash hook error, including PostToolUse:Bash hook error or PostToolUse:Edit hook error when the tool still completed.
  2. If the tool was blocked and stderr shows a real validation message with exit 2, stop here. That is a deliberate block, not the false-positive label.
  3. Note which matcher and script printed nothing on the allow path.

Applies to Windows, Mac, Desktop

Fix 2

Print empty JSON on silent allow exits

Community Confirmed

March 2026 first-hand reports cleared the label when early-exit paths printed echo "{}" before exit 0 instead of producing no stdout. Empty stdout is what the runner treats like an error display condition even when the exit code is 0.

  1. Open the hook script that exits early for non-matching tools or commands.
  2. On every silent allow path, print a no-op JSON object, for example echo "{}", then exit 0.
  3. Keep real block paths on exit 2 with a clear stderr reason.
  4. Re-run the same Bash or Edit action and check whether PreToolUse:Bash hook error is gone.

Applies to Windows, Mac, Desktop

Fix 3

Use modern hookSpecificOutput allow JSON

Community Confirmed

January 2026 first-hand workaround reports say legacy {"decision":"allow"} can still show the phantom error label, while modern hookSpecificOutput with permissionDecision allow does not.

  1. If the hook prints JSON to allow the tool, stop using legacy decision allow alone.
  2. Print modern structured output with continue true and hookSpecificOutput.hookEventName set to PreToolUse plus permissionDecision allow.
  3. Save the script, trigger the same tool once, and confirm the transcript no longer shows PreToolUse:Bash hook error.

Applies to Windows, Mac, Desktop

Fix 4

Verify the hook exit code by hand

Community Confirmed

Reporters pipe sample tool JSON into the script locally to prove exit 0 before blaming Claude Code. That separates a broken script from the false-positive label.

  1. From the project root, pipe a sample tool JSON object into the hook script the same way Claude Code would.
  2. Confirm the exit code is 0 on the allow path and that stdout is either {} or valid modern hook JSON.
  3. If the local exit code is non-zero, fix the script first. The UI label is then a real hook failure.

Applies to Windows, Mac, Desktop

Device notes

Windows
The same echo "{}" and modern JSON leftovers apply on Windows hosts. Prefer absolute interpreter paths in settings.json if the hook command fails before it can print JSON.
Mac
macOS Bash or zsh hook scripts still need a stdout JSON object on silent allow paths.
Desktop
Claude Code CLI on desktop is the surface for this transcript label. Linux desktop builds use the same leftovers.

Official information

Checked on 6 September 2026, Claude Code community issues that quote PreToolUse:Bash hook error describe a false-positive label when hooks exit 0 with empty stdout or legacy allow JSON. Try-today leftovers come from independent January–March 2026 first-hand GitHub reports (echo "{}" on silent exits; modern hookSpecificOutput permissionDecision allow), not from an Anthropic Help article that names this exact sentence.

Sources

Keep troubleshooting

Related problems