PostToolUseFailure
Runs when a tool that started executing fails: the tool threw an error, or an MCP tool returned an error result. Use this to log failures, send alerts, or provide corrective feedback to Claude.
Matches on tool name, same values as PreToolUse.
This event doesn't fire for tool calls rejected before execution: an unknown tool name, input that fails schema or tool-specific validation, or a permission denial. Validation rejections are returned as tool_use_error results and happen before hooks run, so they fire neither PreToolUse nor PostToolUseFailure. Permission denials fire PreToolUse but not this event; see PermissionDenied.
PostToolUseFailure input
PostToolUseFailure hooks receive the same tool_name and tool_input fields as PostToolUse, along with error information as top-level fields. For example, a failed npm test command might deliver:
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PostToolUseFailure",
"tool_name": "Bash",
"tool_input": {
"command": "npm test",
"description": "Run test suite"
},
"tool_use_id": "toolu_01ABC123...",
"error": "Exit code 1\nError: Cannot find module 'express'",
"is_interrupt": false,
"duration_ms": 4187
}| Field | Description |
|---|---|
error | String describing what went wrong. The format depends on the tool that failed |
is_interrupt | Optional boolean. True when the failure reached Claude Code as an abort rather than as an error the tool reported. Cancelling a running tool does not fire this hook; the tool result carries the interruption message instead |
duration_ms | Optional. Tool execution time in milliseconds. Excludes time spent in permission prompts and PreToolUse hooks |
The error string is generally the same text Claude receives as the failed tool's result. Its format varies by tool and failure. Key your hook on tool_name, is_interrupt, and the Exit code N first line; treat the rest of the string as display text, not a stable format.
- For Bash and PowerShell, a command that ran and exited produces a first line
Exit code N, then any output the command produced as one block with stdout and stderr interleaved - A payload may also carry a bare failure message with no exit-code line, when Claude Code could not start the shell process itself
- Claude Code middle-truncates long strings around a
... [N characters truncated] ...marker, and can insert lines of its own, such asCommand timed out after 2m 0s
PostToolUseFailure decision control
PostToolUseFailure hooks can provide context to Claude after a tool failure. In addition to the JSON output fields available to all hooks, your hook script can return these event-specific fields:
| Field | Description |
|---|---|
additionalContext | String added to Claude's context alongside the error. See Add context for Claude |
{
"hookSpecificOutput": {
"hookEventName": "PostToolUseFailure",
"additionalContext": "Additional information about the failure for Claude"
}
}