All symptoms日本語

H01

A Claude Code PreToolUse hook lets the write through when it times out

Symptom

You have a hook that denies writes, yet the file was written. No error or warning on screen or in the JSON result. It happens only when the hook answers later than its timeout.

Check it in 30 seconds

Paste into Windows PowerShell 5.1. It only creates files under your %TEMP% folder. If the last line says REPRODUCED, it happens on your machine. It calls claude once, so it takes about a minute.

$d = Join-Path $env:TEMP ('cc-trap-' + (Get-Date -Format 'yyyyMMddHHmmss')); New-Item -ItemType Directory $d -Force | Out-Null
[IO.File]::WriteAllText("$d\slow-deny.ps1", '[IO.File]::WriteAllText(''MARK'', ''x''); Start-Sleep -Seconds 15; [Console]::Error.WriteLine("denied"); exit 2'.Replace('MARK', "$d\called.txt"))
$hook = 'powershell -NoProfile -ExecutionPolicy Bypass -File \"' + ($d -replace '\\', '/') + '/slow-deny.ps1\"'
[IO.File]::WriteAllText("$d\s.json", '{"hooks":{"PreToolUse":[{"matcher":"Write|Edit","hooks":[{"type":"command","command":"HOOK","timeout":3}]}]}}'.Replace('HOOK', $hook))
Push-Location $d
'Use the Write tool once to create the file written.txt with the content hi. Do not retry if it is blocked.' | claude -p --settings s.json --permission-mode acceptEdits | Out-Null
Pop-Location
$w = Test-Path "$d\written.txt"; $c = Test-Path "$d\called.txt"
"hook denies after 15 s, timeout 3 s: hook called=$c, written=$w"
if (-not $c) { 'CANNOT CHECK (the hook was never called: check disableAllHooks or your settings)' } elseif ($w) { 'REPRODUCED' } else { 'NOT REPRODUCED' }

Why it happens

By default, when a hook times out, crashes or cannot start, Claude Code lets the tool call continue. The official hooks reference says not to count on a stalled hook as a gate. On Windows without Git Bash, though, a failed or timed-out hook without onFailure can block instead (same reference); the author's machine has Git Bash.

Fix

Add "onFailure": "block" to gate hooks (Claude Code 2.1.295 or later). Then a hook that cannot run blocks every write, so test it once. Do not make the timeout too short.

{"type": "command", "command": "...", "timeout": 60, "onFailure": "block"}

On the author's machine

a hook that denies after 15 s with a 3 s timeout let the write through twice; with onFailure: block it was blocked

Author's machine: Windows 11 / Windows PowerShell 5.1.26100 / Python 3.13.7 / Claude Code 2.1.304, Japanese Windows (code page 932). Checked 2026-10-20 to 22.

If you searched for

Related

cc-win-kit bundles the parts that avoid these traps from the start: a write guard (with onFailure: block), an unattended runner, a doctor that scans your files and hook settings, CLAUDE.md templates and the full test suite.

cc-win-kit ($19 on Payhip)

Other symptoms