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
- 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
}
]
}
]
}
}
- 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:"
}
}
- 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
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗