astrid-runtime/astrid · error

policy hook {event} requires a timeout from 200 to 2000 mill

Error message

policy hook {event} requires a timeout from 200 to 2000 milliseconds

What it means

astrid-cli requires policy hooks (hooks whose events are security/policy-relevant, per is_policy_event) to run long enough to be meaningful: a timeout of 0 milliseconds is rejected. The hook timeout must effectively be in the 200–2000 ms range for policy events. This guards against policy hooks being neutered by an instant timeout that would let them be bypassed.

Source

Thrown at crates/astrid-cli/src/commands/hook.rs:74

/// Codex hooks that can gate an operation need a bounded transport wait.
/// Everything else is observation-only and defaults to connect/write/close
/// without an outer timer.
fn is_policy_event(event: &str) -> bool {
    matches!(event, "pre_tool_use" | "permission_request")
}

fn default_timeout_ms(event: &str) -> u64 {
    if is_policy_event(event) {
        DEFAULT_POLICY_TIMEOUT_MS
    } else {
        0
    }
}

fn timeout_for_event(event: &str, requested: Option<u64>) -> Result<u64> {
    let timeout_ms = requested.unwrap_or_else(|| default_timeout_ms(event));
    if is_policy_event(event) && timeout_ms == 0 {
        anyhow::bail!("policy hook {event} requires a timeout from 200 to 2000 milliseconds");
    }
    Ok(timeout_ms)
}

/// Whether a hook transport failure should be surfaced to the host as a
/// failing command. The default is deliberately fail-open so a missing or
/// temporarily unavailable runtime cannot wedge an agent session.
pub(crate) fn fail_closed_requested() -> bool {
    std::env::var(FAIL_CLOSED_ENV).is_ok_and(|value| value == "1")
}

/// Convert a hook-side failure to the host process status according to the
/// explicit fail-closed opt-in.
pub(crate) fn failure_exit_code() -> ExitCode {
    if fail_closed_requested() {
        ExitCode::from(1)
    } else {
        ExitCode::SUCCESS

View on GitHub (pinned to affd8760f4)

Solutions

  1. Set the hook timeout to a value between 200 and 2000 milliseconds in the hook configuration or --timeout flag.
  2. If you intended 'no timeout', use the maximum allowed 2000 ms instead; policy events never permit a zero timeout.
  3. Check default_timeout_ms(event) if no explicit timeout was given — supply an explicit valid timeout to override a zero default.

Example fix

// before
let timeout_ms = 0; // policy hook
// after
let timeout_ms = 500; // within 200..=2000 ms required for policy hooks
Defensive patterns

Strategy: validation

Validate before calling

if is_policy_event(event) && (requested == Some(0)) {
    eprintln!("policy hook '{event}' needs a timeout of 200..=2000 ms");
    return Err(...);
}

Try / catch

match timeout_for_event(event, requested) {
    Ok(ms) => run_hook(event, ms),
    Err(e) => eprintln!("config error: {e:#}"),
}

Prevention

When it happens

Trigger: Calling timeout_for_event(event, requested) with a policy event (is_policy_event(event) == true) where requested is Some(0) or the default_timeout_ms(event) resolves to 0.

Common situations: A developer configures a policy hook with `timeout = 0` (or omits a timeout while a zero default is in play) in hook configuration, or passes --timeout 0 on the CLI, expecting 0 to mean 'no timeout' rather than 'no time'.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/2dab844a38d06118. Report an issue: GitHub.