PreToolUse(Bash) hook returning permissionDecision: "defer" causes "[Tool result missing due to internal error]"

Open 💬 4 comments Opened Jun 1, 2026 by paulcik

Summary

A PreToolUse hook scoped to Bash that returns {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "defer"}} causes every matching Bash tool call to fail with [Tool result missing due to internal error]. The command never executes. Non-deferred decisions (allow, deny, ask) work correctly.

This worked previously and broke without any change to the hook. It persists across full machine restart and extension version downgrade, which points at a harness-side regression in resolving the defer decision rather than a hook or environment issue.

Environment

  • Claude Code VS Code extension 2.1.159 (also reproduced on the prior version via downgrade)
  • macOS (Darwin arm64)
  • Hook configured in ~/.claude/settings.json under hooks.PreToolUse, matcher Bash
  • defaultMode: "auto"

Repro

  1. Add a PreToolUse hook for Bash that prints {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "defer"}} and exits 0.
  2. Have the agent run any Bash command (e.g. echo alive).
  3. Tool call fails immediately with [Tool result missing due to internal error]. The shell never spawns.

Evidence

Extension log (Anthropic.claude-code output channel) at the moment of failure:

[DEBUG] Hook PreToolUse:Bash (PreToolUse) success: {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "defer"}}
[DEBUG] Hook PreToolUse (.../git-guard.py) returned permissionDecision: defer
[DEBUG] Hook result has permissionBehavior=defer

The hook is parsed and validated successfully ("Successfully parsed and validated hook JSON output"), then permissionBehavior=defer is recorded -- but resolution dead-ends instead of falling through to the normal permission system.

Workaround

Disabling the hook (or changing defer -> allow) restores Bash. Neither is acceptable long-term: defer is documented as "fall through to the normal permission system," and allow bypasses the user permission allow-list. The hook in question is a git-safety guardrail, so disabling it removes deployment protections.

Expected

permissionDecision: "defer" should fall through to the configured permission mode / allow-list, exactly as documented, and the command should run (or prompt) accordingly.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗