astrid-runtime/astrid · error
idle timeout must be at most {MAX_RUN_IDLE_TIMEOUT_SECS} sec
Error message
idle timeout must be at most {MAX_RUN_IDLE_TIMEOUT_SECS} seconds What it means
idle_timeout enforces a one-day operational ceiling (MAX_RUN_IDLE_TIMEOUT_SECS). Values above that ceiling are rejected so runaway headless runs cannot idle indefinitely with a nonsensically large timeout.
Source
Thrown at crates/astrid-cli/src/commands/headless.rs:47
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,
message: astrid_types::ipc::IpcMessage,
) -> impl Future<Output = Result<()>> + Send;
}View on GitHub (pinned to affd8760f4)
Solutions
- Lower --idle-timeout to at most 86400 seconds (one day).
- Use 86400 if you want the maximum supported idle window.
- Fix unit conversion in scripts (ms vs s) that inflate the value.
Example fix
// before astrid headless --idle-timeout 999999 // after astrid headless --idle-timeout 86400
Defensive patterns
Strategy: validation
Validate before calling
fn idle_timeout_ok(secs: u64) -> bool {
secs > 0 && secs <= 86400
}
// unit conversion sanity check:
let secs = minutes.checked_mul(60).expect("overflow converting to seconds");
assert!(idle_timeout_ok(secs), "idle timeout exceeds 86400s ceiling"); 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}; cap idle timeout at 86400 seconds"),
} Prevention
- Convert units carefully — seconds, not milliseconds — when generating flags.
- Use 86400 (one day) as the maximum rather than arbitrary large values.
- Add a pre-invocation clamp: min(max(secs, 1), 86400).
When it happens
Trigger: Invoking the headless command with an --idle-timeout value greater than MAX_RUN_IDLE_TIMEOUT_SECS (86400 seconds / one day), or calling idle_timeout with such a value programmatically.
Common situations: Users passing very large numbers (e.g. 999999) assuming more is safer; scripts converting minutes/hours incorrectly (e.g. seconds vs milliseconds); attempting to use the timeout as 'effectively forever'.
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 greater than 0 seconds
- 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/87a11b309e29d16e.
Report an issue: GitHub.