Hook error messages shown on every tool call even when hooks exit 0
Description
All three hook types (PreToolUse, PostToolUse, UserPromptSubmit) display "hook error" messages in the transcript on every tool call, even when the hook scripts exit 0 for non-matching commands. The hooks function correctly (they format files, validate commits, block bad inputs) — but Claude Code reports them as errors anyway.
Expected behavior
Hooks that exit 0 should be silent. "hook error" should only appear for non-zero, non-2 exit codes.
Actual behavior
Every Bash call shows two PreToolUse:Bash hook error messages (one per hook). Every Edit/Write shows PostToolUse:Edit hook error. Every user prompt shows UserPromptSubmit hook error. No detail is provided — just "hook error".
Actions still proceed (not blocked), and the hooks execute their logic correctly.
Hook configuration
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "bash .claude/hooks/validate-commit.sh" },
{ "type": "command", "command": "bash .claude/hooks/validate-issue.sh" }
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "bash .claude/hooks/format-on-save.sh" }
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{ "type": "command", "command": "bash .claude/hooks/session-audit.sh", "timeout": 15 }
]
}
]
}
}
Example hook script (validate-commit.sh)
#!/usr/bin/env bash
# Blocks git commit without issue reference (#NN)
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
echo "$COMMAND" | grep -qE '^git commit' || exit 0
echo "$COMMAND" | grep -qE '\-\-amend|merge' && exit 0
if ! echo "$COMMAND" | grep -qP '#\d+'; then
echo "Commit message must include issue reference (#NN)." >&2
exit 2
fi
exit 0
All hooks follow the same pattern: early exit 0 for non-matching commands, exit 2 to block, exit 0 on success.
Manual testing
Running the hooks manually with sample JSON input returns exit 0 as expected:
echo '{"tool_input":{"command":"git status"}}' | bash .claude/hooks/validate-commit.sh
echo $? # outputs: 0
Transcript excerpt
● Bash(git status -u)
⎿ PreToolUse:Bash hook error
⎿ PreToolUse:Bash hook error
⎿ On branch feat/playground-design-sandbox
...
● Update(~/Work/projects/workout/.claude/hooks/session-audit.sh)
⎿ Removed 1 line
⎿ PostToolUse:Edit hook error
Environment
- Claude Code CLI (latest as of 2026-03-16)
- Linux (WSL2, Ubuntu)
- bash 5.x
- jq installed (
jq-— version string incomplete but functional) - Node 22.x
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗