jdx/mise · error
took longer than s
Error message
took longer than {}s What it means
run_with_limits executes a description command (via a shell) with a hard timeout, polling every 100ms. If the command has not finished when the timeout elapses, mise kills the shell and its process group and bails with 'took longer than Ns'. This prevents a hung describe command from stalling history operations indefinitely.
Solutions
- Increase the describe command's timeout setting to cover realistic worst-case runtime
- Make the describe command non-interactive and fast (avoid prompts, add its own internal timeouts)
- Test the command standalone to find why it hangs, then fix or replace it
Example fix
# before default_config = "slow-describe.sh" # takes > timeout # after: raise the limit or bound the script [history] describe_timeout = "30s" # or make slow-describe.sh finish quickly
Defensive patterns
Strategy: try-catch
Validate before calling
start=$(date +%s); timeout 10 describe-command >/dev/null || echo "describe command exceeds timeout; raise the limit or fix the script" >&2
Try / catch
match history::describe() {
Err(e) if e.to_string().contains("took longer than") => {
// raise timeout or replace the command, then retry once
}
r => r?,
} Prevention
- Keep describe commands fast, deterministic, and non-interactive
- Set timeouts with headroom above worst-case runtime
- Wrap long network calls in the script with their own timeouts
When it happens
Trigger: The describe command configured for history (describe_command) runs longer than the configured timeout in seconds, e.g. a slow script, network call, or a prompt-waiting command.
Common situations: A describe command that prompts for input and blocks forever; commands hitting a slow network resource; timeouts set too low for legitimately slow generators; running on an overloaded CI machine.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- a process it started kept its output open
- command output exceeded
- command output pipes did not close within
- description output exceeded
- exited with
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/af86319dab6db2a5.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/describe_command.rs:168
let stdout = child.stdout.take().expect("piped");
let (sender, receiver) = std::sync::mpsc::channel();
std::thread::spawn(move || {
let mut out = Vec::new();
let _ = stdout.take(DIFF_LIMIT as u64 + 1).read_to_end(&mut out);
let _ = sender.send(out);
});
let started = Instant::now();
let status = loop {
if let Some(status) = child.try_wait()? {
break status;
}
if started.elapsed() >= timeout {
// the shell and whatever it started; the reader thread ends
// with the last writer of the pipe, so it is not waited for
active.0.kill();
let _ = child.kill();
let _ = child.wait();
bail!("took longer than {}s", timeout.as_secs());
}
std::thread::sleep(Duration::from_millis(100));
};
// a descendant that outlived the shell and kept the pipe is not the
// shell's answer: the output is waited for a moment, not forever
let Ok(output) = receiver.recv_timeout(output_grace) else {
active.0.kill();
bail!("a process it started kept its output open");
};
if output.len() > DIFF_LIMIT {
bail!("description output exceeded {} bytes", DIFF_LIMIT);
}
if !status.success() {
bail!("exited with {status}");
}
let Some(line) = first_line(&output) else {
return Ok(None);
};View on GitHub (pinned to 533346cc37)