PreToolUse:Bash hook shows 'hook error' when all handlers return None (exit 0, no output)
Resolved 💬 3 comments Opened Apr 9, 2026 by hey-jhong Closed Apr 13, 2026
Description
When a PreToolUse hook is configured for the Bash matcher, Claude Code displays "PreToolUse:Bash hook error" for every Bash tool call, even when the hook exits with code 0 and produces no output (meaning "allow").
Expected behavior
When a hook exits with 0 and no stdout/stderr, it should be treated as a silent "allow" — no error label should be shown in the UI.
Actual behavior
"PreToolUse:Bash hook error" is displayed before every Bash command output, regardless of the hook's exit code or output.
Steps to reproduce
- Add a PreToolUse hook with
"matcher": "Bash"in.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 my_hook.py PreToolUse",
"statusMessage": "checking..."
}
]
}
]
}
}
- The hook script checks the command and returns nothing (exit 0) for most commands, only outputting JSON for specific blocked/warned commands.
- Every Bash tool call shows "PreToolUse:Bash hook error" in the UI.
Additional context
- Hooks for
Edit|Writematcher work correctly — they show "additional context" or "blocking error" only when the hook outputs JSON. - Outputting explicit
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "allow"}}also shows "hook error". - The hook is used for branch switch protection and destructive command detection — it needs to run for all Bash commands but only produces output for specific patterns.
Environment
- Claude Code CLI (macOS)
- Claude Opus 4.6 (1M context)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗