asyncRewake blocks session startup instead of running in background (docs say "Implies async") — 2.1.246
Summary
A SessionStart command hook declared with "asyncRewake": true blocks session
startup for the full duration of the hook, instead of running in the background.
The hooks reference documents asyncRewake as:
Iftrue, runs in the background and wakes Claude on exit code 2. Impliesasync.
Measured behavior does not match: async: true returns immediately, butasyncRewake: true blocks just like a plain synchronous hook.
Environment
- Claude Code 2.1.246 (CLI on PATH)
- Windows 11, PowerShell 7
- Reproduced in headless mode (
claude -p)
Reproduction
Three otherwise identical projects. Each has a SessionStart hook running a
script that sleeps 75s, writes start/end timestamps to a log, prints a marker to
stdout, and exits (exit code 2 for the asyncRewake variant).
{
"hooks": {
"SessionStart": [
{ "matcher": "startup", "hooks": [
{ "type": "command",
"command": "pwsh -NoProfile -File C:\tmp\probe\hook.ps1",
"shell": "powershell",
"timeout": 240,
"asyncRewake": true }
]}
]
}
}
Then, in each project directory:
claude -p "reply with one word" --permission-mode bypassPermissions
Results
| Hook config | Wall clock until reply | Hook ran to completion | Marker visible to the model |
|---|---|---|---|
| (no flag) | 83.1s | yes (75.0s) | yes |
| "async": true | 6.0s | ran in background | no (expected) |
| "asyncRewake": true | 82.3s | yes (75.0s) | no |
Expected vs actual
Expected: asyncRewake: true returns control immediately (as async: true
does), runs the hook in the background, and wakes Claude on exit code 2.
Actual: startup blocks for the full 75s hook duration. The exit-code-2 wake
also did not surface the hook output to the model, though that part may be
specific to one-shot -p mode — the blocking is the reproducible part.
Why it matters
async: true works correctly and is a good fit for background startup work.asyncRewake looked like the right tool when the background work still needs to
report something back, but because it blocks, adopting it silently reintroduces
the startup cost it is supposed to remove.
Note for anyone hitting this: in the VS Code extension a slow SessionStart
hook causes Subprocess initialization did not complete within 60000ms and the
session dies, while the hook itself keeps running to completion. The CLI and the
desktop app have no such deadline. So a hook that blocks is far more damaging on
that surface than the others.