A prompt blocked by a UserPromptSubmit hook is still sent to the model API in print mode

Status Open
Reported on v2.1.294
Maintainer reply None cached
Activity 0 comments · opened Oct 9, 2026

Version: Claude Code 2.1.294, macOS (Darwin 27.0.0, arm64), model haiku

Steps to reproduce

  1. Make a project with this hook in .claude/settings.json:

``json
{"hooks":{"UserPromptSubmit":[{"hooks":[{"type":"command","command":"python3 hook.py"}]}]}}
`
hook.py prints {"decision": "block", "reason": "blocked"} for a prompt that starts with block`. For other prompts, it prints nothing.

  1. Point ANTHROPIC_BASE_URL at a local recording proxy.
  2. Run claude -p --input-format stream-json --output-format stream-json --verbose with 2 user messages: first block: SECRET-MARKER, then pass: reply with ok.
  3. Look for SECRET-MARKER in the recorded request bodies.

Expected: no request to the model API holds the blocked prompt. The hook blocked it.

Actual: 1 request to /v1/messages, with no tools and 1 message, holds the blocked prompt. It occurred in 9 of 9 runs. The requests of the main conversation do not hold it. In the interactive CLI, no request held the prompt in 9 of 9 runs.

Why it matters: a hook can block a prompt because the prompt must not leave the machine, for example a secret or a message for another system. In print mode, the prompt still goes to the API.

Reproduction script: scripts/spike_hook_display.py in mohanraj00/verbatim-relay. The data is in proofs/spikes/hook-display.json.

I also sent this report with /bug.

View original on GitHub ↗