[BUG] PostToolUse hook JSON output not processed by Claude Code
Environment
- Platform (select one):
- [x] Anthropic API
- [ ] AWS Bedrock
- [ ] Google Vertex AI
- [ ] Other:
- Claude CLI version: 1.0.56 (Claude Code)
- Operating System: macOS 15.5 (Darwin 24.5.0)
- Terminal: Ghostty.app
Bug Description
PostToolUse hooks that output JSON in the documented format are not being processed by Claude Code. The hook correctly outputs JSON with exit code 0, but Claude Code does not make this data available to the AI assistant as documented.
Steps to Reproduce
- Create a PostToolUse hook that outputs JSON in the documented format:
``json``
{"reason": "Hook feedback message"}
- Configure the hook in
.claude/settings.local.json:
``json``
{
"hooks": {
"postToolUse": {
"Bash": "python3 /path/to/hook_script.py"
}
}
}
- Execute a Bash command that triggers the hook (e.g.,
ls) - Hook executes successfully with exit code 0 and outputs the JSON
- Claude Code does not receive/process the JSON output
Expected Behavior
According to the hooks documentation, when a PostToolUse hook returns exit code 0 with JSON output, Claude Code should process that JSON. The AI assistant should have access to the hook's output data.
Actual Behavior
- Hook executes correctly (verified via diagnostic logging)
- Hook outputs proper JSON format (verified by capturing stdout)
- Hook exits with code 0 (success)
- Claude Code does not process the JSON output
- The AI assistant never receives the hook data
Additional Context
This issue has been present since at least version 1.0.44. The hook implementation follows the documented specification exactly:
# Hook outputs JSON and exits with code 0
output = {"reason": "[KSI ⚡3]"}
print(json.dumps(output), flush=True)
sys.exit(0)
Diagnostic logs confirm the hook is working:
2025-07-19T10:30:59.565767 - JSON feedback output: [KSI ⚡3]
But Claude Code is not processing this output as documented. This prevents hooks from providing feedback to the AI assistant during tool execution.
Related Issues:
- #2814 documents other hook system issues
- Hook output visibility is only one part of the broader hooks implementation problems
Workaround:
Currently forced to write diagnostic data to external log files since the documented JSON communication method doesn't work.
12 Comments
A bit counterintuitive, but currently, you also need to specify
"decision": "block"in your PostToolUse hook for Claude Code to show"reason"to Claude. See https://docs.anthropic.com/en/docs/claude-code/hooks#posttooluse-decision-controlIt might make sense to always show "reason" for PostToolUse hooks, so I'll leave this issue open.
Thank you @dicksontsai for the clarification! Adding "decision": "block" to our PostToolUse hook output resolved the issue - the reason field is now properly displayed to Claude.
I agree this behavior is counterintuitive. For future users, if you choose not to always show "reason" for PostToolUse hooks, it might help to clarify the documentation at https://docs.anthropic.com/en/docs/claude-code/hooks#posttooluse-decision-control with something like:
Note: To display a reason field to Claude in PostToolUse hooks, you must include "decision": "block" in your JSON response, even if you're not actually blocking the operation. This is currently required for the reason to be visible in Claude Code's interface.
Or perhaps add a cross-reference in the "PostToolUse hook response format" section that explicitly states this requirement, since developers might naturally assume that omitting decision (allowing the operation) would still show the reason field.
Thanks again for the help! The hook is working perfectly now.
There's an odd side-effect to the way Claude interprets the hook output now, as it appears to Claude as a user prompt:
@durapensa For that use case above, what do you want Claude's behavior to be? Could there be a way to tailor your message to inform Claude that there's nothing actionable?
@dicksontsai, to the best of my knowledge, there's no way I can format "reason" output such that it doesn't appear to Claude as a user message - this is Claude Code behavior.
Perhaps there's a way it could appear as a system message, ideally that's also visible to the user in the main (not ^r) interface?
Yes, that is a good feature request. I'll add it to my backlog.
The PostToolUse hook feedback has stopped appearing in Claude Code's interface, even when using the documented workaround.
Current behavior:
{"decision": "block", "reason": "KSI E:5"}What we're doing:
Previous behavior:
This exact code was working as recently as last week - the "reason" field would appear in Claude's interface as user feedback.
Impact:
Without hook visibility, Claude cannot see real-time system status updates, significantly limiting its ability to assist with development tasks that depend on understanding system state changes.
Environment:
Has there been a recent change to how PostToolUse hooks are processed? The hook is definitely running and outputting the correct JSON, but the feedback is no longer visible to Claude.
This feature still works for me locally on v1.0.61 (the latest public version). What does your debug output look like?
echo_something.py
.claude/settings.local.json
Transcript:
Transcript with debug:
@dicksontsai thanks for the help! I was on vacation last week.
the recent 'PostToolUse hook feedback has stopped appearing' was caused by my hook leaking stdout logging!
I believe I've also cleaned up some [indeterminate] hook output that was triggering:
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
This issue has been automatically closed due to 60 days of inactivity. If you're still experiencing this issue, please open a new issue with updated information.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.