[BUG]

Resolved 💬 3 comments Opened Apr 11, 2026 by communitywireless Closed Apr 14, 2026

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:

  1. 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

  1. Add to settings.json:

{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash ~/.claude/scripts/test-block-hook.sh"
}
]
}
]
}
}

  1. Start Claude Code and ask it to run any bash command:

> run "echo hello"

  1. Expected: The bash command is blocked. Claude sees the reason and does not execute.
  1. 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.
  1. 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.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗