jdx/mise · error
took longer than {}s
Error message
took longer than {}s What it means
`run_with_limits` runs a command inside a shell with a hard timeout. If the command hasn't finished when `elapsed >= timeout`, mise kills the shell and child, then bails with `took longer than {N}s`. A descendant that outlived the shell is additionally given only a bounded output grace rather than waiting forever.
Source
Thrown at src/system/history/describe_command.rs:167
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 afd2eddd3a)
Solutions
- Increase the configured timeout for this command in your history/describe configuration.
- Make the command faster or asynchronous (cache results, skip network calls).
- Fix the underlying hang (e.g. a prompt or daemon child that keeps the pipe open).
- Set the timeout via the relevant env/config knob (e.g. MISE_HISTORY_* timeout settings) if available.
Example fix
# before: describe command that times out [history.describe] command = "curl -s https://slow-api.example.com/status" # after: bound it and raise the timeout timeout = 30 [history.describe] command = "curl -s --max-time 10 https://slow-api.example.com/status"
Defensive patterns
Strategy: retry
Validate before calling
start=$(date +%s); your_slow_command; end=$(date +%s); [ $((end-start)) -lt 30 ] || echo 'will exceed timeout, raise it'
Try / catch
match result {
Err(e) if e.to_string().contains("took longer than") => retry_with_longer_timeout(cmd),
other => other?,
} Prevention
- Size the timeout to the slowest legitimate command
- Avoid network calls in describe commands or cache their results
- Investigate hung descendants that keep pipes open
- Raise the timeout in history/describe config for known-slow commands
When it happens
Trigger: The command passed to the describe/run-with-limits helper runs longer than the configured timeout (in seconds); the poll loop notices the deadline, kills the process group, and returns this error.
Common situations: A describe-command in config invokes a slow script (network calls, package installs) that exceeds the default timeout; a hung child keeps the pipe open causing follow-up output-grace behavior.
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
- expected a checkpoint
- no baseline
- --connect-timeout must be greater than zero
- comparing checkpoints requires git
- checkpoint {} has no content snapshot
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/af86319dab6db2a5.
Report an issue: GitHub.