PreToolUse hook exit code 2 does not block Write tool

Resolved 💬 2 comments Opened May 28, 2026 by stranger2904 Closed Jun 1, 2026

Environment

  • Claude Code (latest, auto-updates channel)
  • macOS Darwin 25.3.0
  • Permission mode: auto
  • skipAutoPermissionPrompt: true in settings

Problem

A PreToolUse hook configured for the Write tool with exit 2 (deny) does not actually block the write. The file is created/modified despite the hook returning a blocking exit code.

Hook configuration (settings.json)

{
  "matcher": "Write",
  "hooks": [{
    "type": "command",
    "command": "/Users/username/.claude/scripts/enforce-local-memory.sh",
    "timeout": 5
  }]
}

Hook script

#!/bin/bash
FILE_PATH="${CLAUDE_TOOL_INPUT_file_path:-}"
if [[ "$FILE_PATH" == *"/.claude/projects/"*"/memory/"* ]]; then
  echo "BLOCKED: Do NOT write memory files to ~/.claude/projects/*/memory/."
  exit 2
fi
exit 0

Manual test

Running the script directly with the matching path correctly outputs "BLOCKED" and exits with code 2.

Actual behavior

Claude writes to ~/.claude/projects/*/memory/*.md successfully. The hook either:

  • Doesn't fire for auto-memory Write calls
  • Fires but exit code 2 isn't enforced
  • The CLAUDE_TOOL_INPUT_file_path env var isn't set correctly

Expected behavior

Write should be blocked when hook returns exit 2.

Possible cause

The auto-memory system may bypass PreToolUse hooks, or the skipAutoPermissionPrompt: true setting may also skip hook enforcement.

View original on GitHub ↗

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