{"record":{"id":"2dab844a38d06118","repo":"astrid-runtime/astrid","slug":"policy-hook-event-requires-a-timeout-from-200-to","errorCode":null,"errorMessage":"policy hook {event} requires a timeout from 200 to 2000 milliseconds","messagePattern":"policy hook (.+?) requires a timeout from 200 to 2000 milliseconds","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/hook.rs","lineNumber":74,"sourceCode":"/// Codex hooks that can gate an operation need a bounded transport wait.\n/// Everything else is observation-only and defaults to connect/write/close\n/// without an outer timer.\nfn is_policy_event(event: &str) -> bool {\n    matches!(event, \"pre_tool_use\" | \"permission_request\")\n}\n\nfn default_timeout_ms(event: &str) -> u64 {\n    if is_policy_event(event) {\n        DEFAULT_POLICY_TIMEOUT_MS\n    } else {\n        0\n    }\n}\n\nfn timeout_for_event(event: &str, requested: Option<u64>) -> Result<u64> {\n    let timeout_ms = requested.unwrap_or_else(|| default_timeout_ms(event));\n    if is_policy_event(event) && timeout_ms == 0 {\n        anyhow::bail!(\"policy hook {event} requires a timeout from 200 to 2000 milliseconds\");\n    }\n    Ok(timeout_ms)\n}\n\n/// Whether a hook transport failure should be surfaced to the host as a\n/// failing command. The default is deliberately fail-open so a missing or\n/// temporarily unavailable runtime cannot wedge an agent session.\npub(crate) fn fail_closed_requested() -> bool {\n    std::env::var(FAIL_CLOSED_ENV).is_ok_and(|value| value == \"1\")\n}\n\n/// Convert a hook-side failure to the host process status according to the\n/// explicit fail-closed opt-in.\npub(crate) fn failure_exit_code() -> ExitCode {\n    if fail_closed_requested() {\n        ExitCode::from(1)\n    } else {\n        ExitCode::SUCCESS","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/hook.rs#L56-L92","documentation":"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.","triggerScenarios":"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.","commonSituations":"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'.","solutions":["Set the hook timeout to a value between 200 and 2000 milliseconds in the hook configuration or --timeout flag.","If you intended 'no timeout', use the maximum allowed 2000 ms instead; policy events never permit a zero timeout.","Check default_timeout_ms(event) if no explicit timeout was given — supply an explicit valid timeout to override a zero default."],"exampleFix":"// before\nlet timeout_ms = 0; // policy hook\n// after\nlet timeout_ms = 500; // within 200..=2000 ms required for policy hooks","handlingStrategy":"validation","validationCode":"if is_policy_event(event) && (requested == Some(0)) {\n    eprintln!(\"policy hook '{event}' needs a timeout of 200..=2000 ms\");\n    return Err(...);\n}","typeGuard":null,"tryCatchPattern":"match timeout_for_event(event, requested) {\n    Ok(ms) => run_hook(event, ms),\n    Err(e) => eprintln!(\"config error: {e:#}\"),\n}","preventionTips":["Never set timeout = 0 for policy hooks; 0 does not mean 'no timeout'.","Clamp configured timeouts to 200..=2000 before passing them to the CLI.","Give policy hooks explicit timeouts instead of relying on defaults."],"tags":["cli","hooks","timeout","validation"],"backgroundTag":"value-out-of-range","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}