PreToolUse hook returning permissionDecision: 'defer' silently parks the tool and surfaces as '[Tool result missing due to internal error]'
Summary
When a PreToolUse hook returns permissionDecision: "defer" and the session is flagged isNonInteractiveSession, the tool call is parked and never runs. The model receives [Tool result missing due to internal error] — an opaque message that gives no indication a hook deferred the call.
Two things make this hard to diagnose:
- The Claude desktop app is flagged non-interactive even with a human present. So
defer— documented in-code as "print-mode only" — is actually honored in a live, interactive-feeling desktop session. - The failure is silent and misattributed. "Internal error" reads like a transport/platform fault, not "your hook parked this call". The interactive path logs a helpful warning (
ignoring (defer is print-mode only)); the non-interactive path that actually parks the tool logs nothing the user sees.
This bit AskUserQuestion particularly hard: the decision-card UI never appears, so the human is never asked anything and the agent silently proceeds without an answer.
Repro
- Register a
PreToolUsehook matchingAskUserQuestionthat prints:
``json``
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"defer"}}
- Run in the Claude desktop app (not the terminal CLI).
- Have the model call
AskUserQuestion.
Expected: the decision card renders, or a clear message explaining the call was deferred by a hook.
Actual: no card, and the model receives [Tool result missing due to internal error].
Removing permissionDecision (or running the same hook in the terminal CLI, where defer is ignored) makes it work.
Observed on Claude Code 2.1.221, macOS 25.5.0. In one transcript history, 3,700+ calls to every other tool resolved 100% while all 8 AskUserQuestion calls returned no result.
Suggested improvements
- Surface a specific error when a tool is parked by a hook — e.g. "Tool call deferred by PreToolUse hook
<name>" — instead of the generic internal-error string. - Consider whether
AskUserQuestionshould be exempt fromdeferparking, since parking it converts "ask the human" into "silently don't ask". - Reconsider whether the desktop app should report
isNonInteractiveSession: truewhen a human is present and able to answer prompts;deferis documented as print-mode only, but this session type gets the print-mode behavior. - Optionally warn at hook-registration time that
deferis print-mode only.
Found while debugging gstack, whose AskUserQuestion PreToolUse hook emits defer as its "no opinion" signal. Filing separately there.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗