[BUG] PostToolUse hooks do not fire on failed Bash commands (non-zero exit code)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
PostToolUse hooks do not fire when a Bash command exits with a non-zero exit code. The hook only fires on successful (exit 0) tool completions, silently skipping failures.
This was previously reported in #16282 (auto-closed as stale on 2026-03-01), #16599, and #6371. The bug is still present in v2.1.63. Filing fresh per the stale-bot's instructions.
What Should Happen?
PostToolUse should fire after all Bash tool completions, including failures. The hook payload should include success/failure context (e.g., "success": false, exit code, stderr) so hook consumers can distinguish outcomes.
A "post" hook that only fires on success is semantically a PostToolUseSuccess hook — not a general post-hook. Every standard use case for post-event hooks (logging, cleanup, analytics, error handling) requires firing on all completions.
Error Messages/Logs
# Hook log after running 3 Bash commands (success, failure, success):
12:31:17 PostToolUse fired for: Bash ← echo PASS_1 (exit 0)
← ls ./nonexistent_xyz (exit 1) — MISSING
12:31:22 PostToolUse fired for: Bash ← echo PASS_2 (exit 0)
# Expected: 3 entries. Actual: 2. Failed command produced no hook invocation.
Steps to Reproduce
Minimal, self-contained reproduction using only claude CLI and .claude/settings.json:
# 1. Setup
mkdir -p /tmp/hook-bug-repro/.claude
cat > /tmp/hook-bug-repro/hook.sh << 'HOOKEOF'
#!/bin/bash
INPUT=$(cat)
TOOL=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_name','?'))" 2>/dev/null)
echo "$(date '+%H:%M:%S') PostToolUse fired for: $TOOL" >> /tmp/hook-bug-repro/hook.log
HOOKEOF
chmod +x /tmp/hook-bug-repro/hook.sh
cat > /tmp/hook-bug-repro/.claude/settings.json << 'SETEOF'
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [{"type": "command", "command": "bash /tmp/hook-bug-repro/hook.sh"}]
}
]
}
}
SETEOF
# 2. Run (3 Bash commands: success → failure → success)
cd /tmp/hook-bug-repro
rm -f hook.log
claude -p 'Run these 3 bash commands in separate tool calls:
1. echo PASS_1
2. ls ./nonexistent_xyz
3. echo PASS_2
Command 2 WILL fail — that is intentional.' --allowedTools 'Bash(command:*)'
# 3. Verify
cat /tmp/hook-bug-repro/hook.log
# Expected: 3 log entries (one per command)
# Actual: 2 log entries (failed command skipped)
Claude Model
Opus
Is this a regression?
I don't know
Claude Code Version
2.1.63 (Claude Code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
iTerm2
Additional Information
Prior issues (all still unresolved):
- #16282 — Original report, auto-closed as stale (closing comment)
- #16599 — Consolidated into #16282
- #6371 — Original tracking issue
Use cases blocked by this bug:
- Automated failure logging / learning-from-mistakes workflows
- Hook-based error detection and notification (e.g., sound alerts on failure)
- CI-style failure reporting
- Analytics that need complete tool usage data
- Automated remediation hints based on stderr parsing
Suggested fix (Option B from #16282): Extend PostToolUse to always fire, with a success boolean and failure context:
{
"tool_name": "Bash",
"tool_input": {"command": "ls ./nonexistent"},
"success": false,
"tool_response": {
"stdout": "",
"stderr": "ls: ./nonexistent: No such file or directory",
"exit_code": 1
}
}
As noted in #16282 comment, a trigger field ("success" | "failure" | "both", defaulting to "success") would preserve backward compatibility for existing hooks.
4 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
related issues are not duplicate
because the issue is still not solved at all
You'll need to use the
PostToolUseFailedhook to handle failed Bash commands.PostToolUsehooks only trigger on successful tool calls.Docs: https://code.claude.com/docs/en/hooks#posttooluse
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.