Hmbown/CodeWhale · error · io::Error
hook helper did not finish within its timeout
Error message
hook helper did not finish within its timeout
What it means
This error means a hook helper subprocess did not exit within its allotted timeout. The library kills and reaps the child (kill_and_reap_immediate_child with HOOK_REAP_TIMEOUT) and then throws TimedOut, since a hook exceeding its deadline is treated as failed.
Solutions
- Increase the hook's configured timeout to cover realistic helper runtime
- Fix the helper so it terminates: close stdin, remove interactive prompts, add its own internal timeouts
- Remove or gate the slow hook if it cannot be made deterministic
Example fix
// before
{"command": "slow-linter --remote", "timeout_ms": 1000}
// after
{"command": "slow-linter --offline", "timeout_ms": 10000} Defensive patterns
Strategy: try-catch
Validate before calling
// before spawning: ensure the helper is non-interactive and bounded e.g. assert the hook command runs with stdin closed and has its own deadline
Try / catch
match wait_with_timeout(child, configured_timeout) {
Ok(status) if status.success() => proceed(),
Ok(status) => report_hook_failure(status),
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
eprintln!("hook exceeded its timeout; increase timeout_ms or fix the helper");
}
Err(e) => return Err(e.into()),
} Prevention
- Size each hook's timeout to measured worst-case runtime
- Ensure hook helpers never read stdin or prompt interactively
- Give slow helpers (network linters, builds) internal timeouts and offline modes
When it happens
Trigger: A hook command spawned by the executor (wait_timeout with the configured hook timeout) still running when the deadline elapses — e.g. a network call, a long build, or an interactive prompt blocking the helper.
Common situations: A hook script waits on stdin (no tty) and hangs; a formatter/linter hits a slow network; the hook timeout is configured too aggressively for a legitimately slow helper.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Command timed out after
- powershell timed out after
- timeout after ms
- AT-SPI action failed
- background hook supervisor is unavailable
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/b87ac38c13f3b230.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/hooks/executor.rs:1114
if status.success() {
Ok(())
} else {
Err(std::io::Error::other(format!(
"taskkill exited with {status}"
)))
}
}
#[cfg(any(windows, test))]
fn wait_for_helper_status(
child: &mut Child,
timeout: Duration,
) -> std::io::Result<std::process::ExitStatus> {
match child.wait_timeout(timeout)? {
Some(status) => Ok(status),
None => {
let _ = kill_and_reap_immediate_child(child, HOOK_REAP_TIMEOUT);
Err(std::io::Error::new(
std::io::ErrorKind::TimedOut,
"hook helper did not finish within its timeout",
))
}
}
}
fn kill_and_reap_immediate_child(child: &mut Child, timeout: Duration) -> bool {
let _ = child.kill();
matches!(child.wait_timeout(timeout), Ok(Some(_)))
}
/// Spawn a contained hook child.
///
/// Errors returned here are deliberately free of the hook command, the
/// resolved interpreter path, and the OS message: the caller turns them into a
/// user-visible "hook could not answer" receipt, and on Windows a raw spawn
/// error echoes the whole command line back. The detail is logged instead.View on GitHub (pinned to 73e0f67d83)