jdx/mise · error

timed out after {timeout:?}

Error message

timed out after {timeout:?}

What it means

Raised by the bounded/isolated command reader (read_isolated in src/cmd/bounded.rs) when the spawned child does not finish before the configured timeout elapses. The child process and its process tree are killed first (end()), then a timeout error is returned. It guards mise against hanging on a stuck subprocess.

Source

Thrown at src/cmd/bounded.rs:49

        // allocate twice what was asked before anyone objected.
        let budget = AtomicUsize::new(limit);
        let result = tokio::time::timeout(timeout, async {
            tokio::try_join!(
                child.wait(),
                capture(stdout, &budget, limit),
                capture(stderr, &budget, limit)
            )
        })
        .await;
        let (status, stdout, _stderr) = match result {
            Ok(Ok(output)) => output,
            Ok(Err(err)) => {
                end(&mut child, tree).await;
                return Err(err.into());
            }
            Err(_) => {
                end(&mut child, tree).await;
                bail!("timed out after {timeout:?}");
            }
        };
        if !status.success() {
            bail!("command exited with non-zero status: {status}");
        }
        Ok(String::from_utf8(stdout)?.trim_end().to_string())
    }
}

/// How long reaping a killed command may take before it is left to the
/// operating system. A process that has been killed is normally gone at
/// once; one that is not is no reason to outlive the deadline.
const REAP: Duration = Duration::from_secs(1);

/// End the command and account for it, without waiting on a process that
/// may not be listening. Closing the tree kills the group, but the direct
/// child can be outside it — on Windows it may never have joined the job,
/// and on unix it can have left the group — and `kill_on_drop` cannot run

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Increase the timeout value at the call site if the command is legitimately slow
  2. Fix the underlying command so it completes unattended (remove interactive prompts)
  3. Check network/proxy availability if the command fetches remote data
  4. Investigate the stuck process tree; the child is killed, so look at what it was waiting on

Example fix

// before
read_isolated(&mut cmd, Duration::from_secs(5), &tree).await?
// after
read_isolated(&mut cmd, Duration::from_secs(60), &tree).await?
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the command can run unattended and quickly: smoke-test it first
// e.g. time out manually before wiring it into mise
timeout 10 <command> --version || echo "command may hang"

Try / catch

match read_isolated(&mut cmd, timeout, &tree).await {
    Ok(out) => out,
    Err(e) if e.to_string().starts_with("timed out after") => {
        // retry once with a larger timeout or fall back to a cached value
        retry_with_timeout(timeout * 4).await.unwrap_or_else(|_| cached_value())
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Any call into read_isolated where the child command blocks (reads stdin, waits on network, deadlock) longer than the `timeout` duration passed to the function.

Common situations: A tool-version listing command hangs on a slow/unreachable network; a plugin script prompts for input while stdin is captured; a wedged daemon holds the child open.

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


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/36aeb5227efd8c10. Report an issue: GitHub.