[BUG]
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?
PreToolUse hook permissionDecision 'block'/'deny' is ignored — tool executes regardless
Description
PreToolUse hooks returning permissionDecision: "deny" or "block" in the hookSpecificOutput JSON do not prevent tool execution. The hook fires correctly, returns valid JSON with the deny/block decision, exits with code 0, but Claude Code ignores the decision and executes the tool anyway.
Environment
- Claude Code version: 2.1.101
- OS: Windows 11 (Git Bash)
- Model: claude-sonnet-4-5, claude-opus-4-6
Reproduction
settings.json hook config:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Agent",
"hooks": [
{
"type": "command",
"command": "bash ~/.claude/scripts/sdlc-gate-hook.sh"
}
]
}
]
}
}
Hook script returns valid JSON:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "block",
"permissionDecisionReason": "PREFLIGHT CHECK: Confirm before proceeding."
}
}
Expected behavior:
The Agent tool call should be blocked. Claude should see the permissionDecisionReason and NOT execute the tool.
Actual behavior:
The hook fires, the JSON is returned correctly (verified via logging), but Claude Code ignores the permissionDecision: "block" and executes the Agent tool anyway. The advisory text appears in a system reminder but the tool is not blocked.
I've also tried "deny", exit code 2, and "continue": false — none of them prevent execution.
Impact
This breaks any workflow that uses PreToolUse hooks for governance, security, or process enforcement. I'm building an SDLC enforcement system that requires a developer to confirm a checklist before dispatching subagents. Without working deny/block, the hook can only advise — it can't enforce.
Related Issues
- #4669 (closed as NOT_PLANNED) — same issue reported by multiple users
- #37210 — same issue specifically for Edit tool
The previous issue was closed without resolution. This is a fundamental broken contract in the hook API — the documentation says hooks can block tool execution, but they can't. This affects anyone building governance tooling on top of Claude Code hooks.
Workaround
None that preserves the hook-based architecture. The only workaround is moving to a framework where we control the tool execution pipeline directly (e.g., Pydantic AI with SkipToolExecution).
What Should Happen?
Expected behavior:
The Agent tool call should be blocked. Claude should see the permissionDecisionReason and NOT execute the tool.
Error Messages/Logs
Steps to Reproduce
Steps to reproduce the PreToolUse block bug:
- Create a test hook script:
# Save as ~/.claude/scripts/test-block-hook.sh
#!/usr/bin/env bash
cat <<'EOF'
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "block", "permissionDecisionReason": "TEST: This tool call should be blocked."}}
EOF
exit 0
- Add to settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash ~/.claude/scripts/test-block-hook.sh"
}
]
}
]
}
}
- Start Claude Code and ask it to run any bash command:
> run "echo hello"
- Expected: The bash command is blocked. Claude sees the reason and does not execute.
- Actual: The hook fires, returns the block JSON, but Claude Code executes echo hello anyway. The block reason may appear as a system reminder but the tool is not prevented from running.
- Also try with "deny" and exit code 2:
#!/usr/bin/env bash
echo '{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "TEST: Denied."}}'
exit 2
Same result — tool executes regardless.
---
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.101
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
Without a harness that stops unwanted execution Claude is a freaking disaster waiting to happen. The agent needs to be wrapped in programmatic enforcement if it is going to follow the full SDLC process. Not being able to use these hooks makes it that much harder to prevent it from going rampaging through the code without following procedures., Please fix.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗