PostToolUse hook block message displayed twice for single hook execution

Resolved 💬 2 comments Opened Mar 6, 2026 by nathanvale Closed Mar 6, 2026

Description

When a PostToolUse hook returns a decision: "block" JSON response, Claude Code displays the blocking error message twice in the conversation, even though the hook only executes once.

Steps to reproduce

  1. Create a plugin with a PostToolUse hook that returns a block decision:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "bun run ${CLAUDE_PLUGIN_ROOT}/hooks/my-check.ts",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
  1. The hook outputs a single JSON block to stdout:
{
  "decision": "block",
  "reason": "1 Biome error(s) in edited files",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "file.ts:0 [format] Formatter would have printed the following content:"
  }
}
  1. Trigger the hook by editing a file that causes the hook to block.

Expected behavior

One block message displayed:

PostToolUse:Edit hook blocking error from command: "bun run .../hooks/my-check.ts": 1 Biome error(s) in edited files

Actual behavior

Two identical block messages displayed:

PostToolUse:Edit hook blocking error from command: "bun run .../hooks/my-check.ts": 1 Biome error(s) in edited files

PostToolUse:Edit hook blocking error from command: "bun run .../hooks/my-check.ts": 1 Biome error(s) in edited files

The additionalContext only appears once (correct), but the top-level block reason is duplicated.

Verification

Added a debug log to the hook that appends a unique run ID to a temp file on each invocation. After triggering the hook, the file contained exactly one entry, confirming the hook executes once but the message is rendered twice.

Environment

  • Claude Code version: 2.1.69
  • Platform: macOS (Darwin 25.3.0, Apple Silicon)
  • Shell: zsh
  • Hook runner: Bun

View original on GitHub ↗

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