Stop hook breaks -p (print/pipe) mode — output is silently empty
Resolved 💬 3 comments Opened Mar 25, 2026 by jeanpralo Closed Apr 19, 2026
Bug Description
Any Stop hook configured in ~/.claude/settings.json causes claude -p (print/pipe mode) to return empty output. The model processes the request and consumes tokens, but no text reaches stdout.
Reproduction Steps
- Add a Stop hook to
~/.claude/settings.json:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "say 'Done'"
}
]
}
]
}
}
- Run:
echo "say hello" | claude -p - Expected: Text output (e.g., "Hello! How can I help you today?")
- Actual: No output at all
Key Findings
- The model does generate a response — confirmed via
--verbose --output-format stream-json, which shows the assistant message with valid text content (e.g.{"type":"text","text":"HELLO WORLD"}) - However, the final
resultfield in the JSON output is an empty string"" - Tokens are consumed and billed normally
- Even a no-op Stop hook (
"command": "true") triggers the bug — it's not about what the hook does, but the mere presence of a Stop hook entry - The
Notificationhook does not cause this issue — onlyStop - Setting
"Stop": [](empty array) works around the issue - Affects both opus and sonnet models
- Reproducible from any working directory (not related to CLAUDE.md or project config)
Environment
- Claude Code version: 2.1.83
- Platform: macOS (Darwin 24.6.0)
- Shell: zsh
Workaround
Remove or empty the Stop hook array in settings:
"Stop": []
This restores -p mode output but loses the Stop hook functionality (e.g., audio notification when interactive sessions complete).
Impact
This silently breaks any scripts or automation using claude -p when the user also has Stop hooks configured for interactive use. There's no way to conditionally apply hooks for interactive vs pipe mode, and no error is surfaced — output is just empty.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗