astrid-runtime/astrid · error
idle timeout must be greater than 0 seconds
Error message
idle timeout must be greater than 0 seconds
What it means
The headless runner's idle_timeout converts a whole-second CLI value into a Duration. Zero is rejected because a 0-second idle timeout would invalidate runs immediately — the run must be given a positive idle window.
Source
Thrown at crates/astrid-cli/src/commands/headless.rs:44
pub(crate) enum HeadlessError {
/// No active-run message arrived within the configured idle budget.
#[error("timed out waiting for response after {timeout_secs}s idle")]
IdleTimeout {
/// The configured idle budget in whole seconds.
timeout_secs: u64,
},
/// The daemon connection failed while collecting the response.
#[error(transparent)]
Read(#[from] anyhow::Error),
}
/// Validate and convert a whole-second run idle timeout.
///
/// # Errors
/// Returns an error for zero or values above the one-day operational ceiling.
pub(crate) fn idle_timeout(timeout_secs: u64) -> Result<Duration> {
if timeout_secs == 0 {
anyhow::bail!("idle timeout must be greater than 0 seconds");
}
if timeout_secs > MAX_RUN_IDLE_TIMEOUT_SECS {
anyhow::bail!("idle timeout must be at most {MAX_RUN_IDLE_TIMEOUT_SECS} seconds");
}
Ok(Duration::from_secs(timeout_secs))
}
/// Source of daemon messages consumed by headless response collection.
pub(crate) trait ResponseSource {
/// Read the next daemon message or report timeout at the source boundary.
fn read_message_before(
&mut self,
remaining: Duration,
) -> impl Future<Output = ReadOutcome> + Send;
/// Send a message to the daemon.
fn send_message(
&mut self,View on GitHub (pinned to affd8760f4)
Solutions
- Pass a positive integer of seconds, e.g. --idle-timeout 60.
- If 'no timeout' is intended, use the maximum allowed value (up to the one-day ceiling) rather than 0.
- Fix the script/flag source so the computed timeout is never 0.
Example fix
// before astrid headless --idle-timeout 0 // after astrid headless --idle-timeout 300
Defensive patterns
Strategy: validation
Validate before calling
fn idle_timeout_ok(secs: u64) -> bool {
secs > 0 && secs <= 86400
}
// guard before invoking the CLI:
assert!(idle_timeout_ok(secs), "idle timeout must be 1..=86400 seconds"); Type guard
fn parse_idle_timeout(raw: &str) -> Option<u64> {
raw.parse::<u64>().ok().filter(|s| *s > 0 && *s <= 86400)
} Try / catch
match idle_timeout(secs) {
Ok(d) => run_with_timeout(d).await,
Err(e) => eprintln!("astrid: {e}; pass a whole number of seconds in 1..=86400"),
} Prevention
- Clamp computed timeouts to >= 1 second in scripts.
- Document that 0 is invalid — use the max value instead of 0 for long windows.
- Validate flags at the script boundary before shelling out to the CLI.
When it happens
Trigger: Invoking the headless command (or calling idle_timeout directly) with --idle-timeout 0 or an equivalent zero-second value.
Common situations: Scripts parameterizing the timeout where a computed value evaluates to 0; users passing 0 assuming it means 'no timeout' (it does not); copy-pasted flags with a placeholder left at 0.
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.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- idle timeout must be at most {MAX_RUN_IDLE_TIMEOUT_SECS} sec
- policy hook {event} requires a timeout from 200 to 2000 mill
- --retain-entries must be at least 1
- --retain-bytes must be greater than 0
- --var has an empty key (got {item:?})
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/b8b77a50793af91e.
Report an issue: GitHub.