Gotchas Around Hooks
Common Hook Pitfalls
Hooks are powerful but have several subtle gotchas that can lead to unexpected behavior. Understanding these upfront saves significant debugging time.
| Gotcha | What Happens | Solution |
|---|---|---|
| Not restarting Claude | Hook changes are ignored silently | Always restart after config or script changes |
| Wrong tool name in matcher | Hook never fires | Ask Claude for exact tool names, test with logging |
| Post-hook trying to block | Exit code 2 is ignored | Only pre-hooks can block; post-hooks just provide feedback |
| Missing stdin handling | Script crashes with parse error | Always wrap JSON.parse in try/catch |
| Slow hook script | Claude Code feels sluggish | Keep hooks fast (<500ms); avoid network calls in pre-hooks |
| Wrong path field | File check misses some tools | Check file_path, path, and pattern fields |
Hook gotchas and their solutions
Fail-Open Design
If your hook script crashes or returns an unexpected exit code, Claude Code treats it as 'allow' (fail-open). This is a safety feature -- a buggy hook won't permanently lock Claude out of tools. But it means you should test hooks thoroughly to ensure they actually block what they're supposed to.
Debugging Hooks
When a hook isn't working as expected, add temporary logging to understand what data it receives and what decisions it makes.
// Temporary debug logging for hooks
const fs = require('fs');
const input = fs.readFileSync('/dev/stdin', 'utf8');
const data = JSON.parse(input);
// Log to a file (not stdout/stderr, which go to Claude)
fs.appendFileSync(
'./hooks/debug.log',
JSON.stringify(data, null, 2) + '\n---\n'
);
// Now check debug.log to see exact tool call data
process.exit(0);Log to File, Not Console
When debugging, write logs to a file rather than console.log (stdout) or console.error (stderr). Stdout is ignored by Claude Code, and stderr is treated as feedback to Claude, which can confuse the conversation.
Key Takeaways
- ✓Always restart Claude Code after any hook configuration or script changes
- ✓Hooks are fail-open: crashes or unexpected exit codes are treated as 'allow'
- ✓Only pre-hooks can block tool calls (exit code 2); post-hooks provide feedback only
- ✓Keep hook scripts fast (<500ms) to avoid making Claude Code feel sluggish
- ✓Debug by logging to a file, not stdout/stderr, to avoid interfering with Claude communication
Check Your Understanding
Test what you learned in this lesson.
Q1.Your hook script crashes with an unhandled exception. What happens to Claude's tool call?
Q2.When debugging a hook, why should you log to a file instead of using console.log()?
Q3.A hook that makes an API call takes 3 seconds to complete. What impact does this have?