PostToolUse async hook invocations partially dropped on consecutive Write/Edit batches (Windows, 2.1.139)
Summary
PostToolUse hook invocations are partially dropped when a session performs consecutive or parallel Write/Edit tool calls. In a measured batch, only 6 of 12 matching edits triggered the hook. No error is surfaced anywhere — the missing invocations simply never happen.
This is distinct from the "hooks never fire" reports (#55644, closed as dup of #6305): wiring is correct and the hook does fire — just not for every matched tool call.
Environment
- Claude Code 2.1.139 (Windows desktop app)
- Windows 11 Pro 10.0.26200
- Hook runtime: Windows PowerShell 5.1
Configuration (~/.claude/settings.json, sanitized)
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "powershell -NoProfile -File C:/Users/XXX/.claude/hooks/mirror-plan.ps1",
"async": true,
"timeout": 30,
"statusMessage": "Mirroring memory"
}
]
}
]
The hook script reads the JSON payload from stdin and appends a line to a local log file for every invocation whose file_path matches a directory filter, then scps the file to a backup host.
Observed behavior
- A session performing a batch of 12
Edit/Writecalls to files matching the filter produced only 6 log entries (hook script logs immediately after the path filter, before any network I/O — so the missing 6 were never invoked, not failed mid-run). - Occasionally a single, isolated
Editalso produces no invocation (observed same day in a different session; same config, hook proven working minutes later via manual stdin invocation and via other edits). - When invocations do run, they complete quickly (<2 s) and exit 0, well within the 30 s timeout.
- No errors in the session transcript, no partial log lines, nothing to indicate the dropped calls ever started.
Expected behavior
One hook invocation per matched tool call — or, if async hooks are intentionally coalesced/debounced under load, documentation of that behavior (it currently silently breaks "mirror on every write"-style hooks).
Workaround
Post-batch reconciliation: count log entries vs. edits performed, then manually re-invoke the hook (pipe the JSON payload to the script via stdin) for the files that were missed.
Notes
- Possibly related to
async: truescheduling; not yet tested whether synchronous hooks drop calls the same way. - Ref: #55644 (closed as duplicate of #6305 — that report was "never fires"; this one is "fires for a subset").
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗