jlcodes99/cockpit-tools · error · std::io::Error
TimedOut
TimedOut
Error message
process timed out after {:?} What it means
output_with_timeout runs a child process while polling for completion; when the process exceeds the given timeout it is killed, pipe readers are dropped without joining (a surviving descendant may hold the inherited pipe), and an io::Error of kind TimedOut with 'process timed out after {timeout:?}' is returned. It is the generic bounded command runner used by completes_fast_command and related helpers.
Source
Thrown at src-tauri/src/modules/process_timeout.rs:50
std::thread::spawn(move || {
let mut output = Vec::new();
pipe.read_to_end(&mut output).map(|_| output)
})
});
let deadline = Instant::now() + timeout;
let status = loop {
match child.try_wait() {
Ok(Some(status)) => break status,
Ok(None) => {
if Instant::now() >= deadline {
let _ = child.kill();
let _ = child.wait();
// Do not join readers on the kill path: a surviving descendant may
// still hold an inherited pipe, and the timeout path must stay bounded.
drop(stdout_reader);
drop(stderr_reader);
return Err(io::Error::new(
io::ErrorKind::TimedOut,
format!("process timed out after {:?}", timeout),
));
}
std::thread::sleep(Duration::from_millis(20));
}
Err(error) => {
let _ = child.kill();
let _ = child.wait();
drop(stdout_reader);
drop(stderr_reader);
return Err(error);
}
}
};
let stdout = join_reader_with_deadline(stdout_reader, deadline)?;
let stderr = join_reader_with_deadline(stderr_reader, deadline)?;View on GitHub (pinned to 1ed8b77992)
Solutions
- Raise the timeout Duration to fit the command's worst-case runtime.
- Retry the command once with a larger budget if transient slowness is plausible.
- Investigate why the child hangs (stdin waiting? network? prompt?) and fix the invocation (e.g. pipe stdin, add non-interactive flags).
- Handle the TimedOut error explicitly and fall back to a default result instead of propagating.
Example fix
// before
let out = output_with_timeout(&mut cmd, Duration::from_secs(3))?;
// after
match output_with_timeout(&mut cmd, Duration::from_secs(10)) {
Ok(out) => out,
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
eprintln!("command exceeded 10s, using default");
default_output()
}
Err(e) => return Err(e),
} Defensive patterns
Strategy: try-catch
Try / catch
match output_with_timeout(&mut cmd, timeout) {
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
eprintln!("command exceeded {:?}; using fallback", timeout);
fallback()
}
other => other,
} Prevention
- Set timeouts above the command's realistic worst-case duration
- Run commands non-interactively (pipe stdin, disable prompts) so they cannot hang waiting for input
- Measure actual command latency and calibrate the timeout empirically
- For network-bound commands, add their own connect/read timeouts so the outer kill is a last resort
When it happens
Trigger: Calling output_with_timeout (or completes_fast_command) with a command that runs longer than the supplied Duration — e.g. a hung child, infinite-running command, or timeout set too short.
Common situations: Probing whether a command 'completes fast' when the command actually hangs; network-bound CLIs stalling; timeout budget miscalibrated for slow machines.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05).
Data as JSON: /api/errors/02ffa8369eb2c075.
Report an issue: GitHub.