PreToolUse hooks with exit code 2 don't block Write/Edit operations
Bug Description
PreToolUse hooks that return exit code 2 properly block Bash tool operations but do not block Write or Edit tool operations. The hook runs, finds violations, outputs to stderr, and returns exit 2 - but the file is still created/modified.
Steps to Reproduce
- Create a PreToolUse hook registered for
Edit|Writematcher - Hook should analyze content and return exit code 2 with stderr message
- Attempt to use the
Writetool to create a file that should be blocked
Expected Behavior
When a PreToolUse hook returns exit code 2, the Write/Edit operation should be blocked (same behavior as Bash tool).
Actual Behavior
- Bash tool: PreToolUse exit code 2 → Operation blocked ✅
- Write tool: PreToolUse exit code 2 → File created anyway ❌
- Edit tool: PreToolUse exit code 2 → Edit applied anyway ❌
The hook runs and the error message appears in the output, but the operation completes.
Workaround
Using PostToolUse hooks to detect violations after the file is written and display an error message. This provides feedback but doesn't prevent the violation.
Environment
- Claude Code version: Latest (December 2025)
- OS: macOS Darwin 25.1.0
- Hook type: Python script returning exit code 2
Hook Example
#!/usr/bin/env python3
import json
import sys
data = json.load(sys.stdin)
if data.get('tool_name') == 'Write':
# Check for violation...
if has_violation:
print("Error: Violation detected", file=sys.stderr)
sys.exit(2) # Should block but doesn't
sys.exit(0)
Related Issues
This may be related to #3514 (PreToolUse hooks with preventContinuation:true are not blocking tool execution)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗