xai-org/grok-build · error
command timed out after {}s
Error message
command timed out after {}s What it means
run_capped executes a provider auth command under tokio::time::timeout, capturing stdout/stderr. If the command does not finish within the timeout, the process group is killed and this error reports the timeout in seconds. It fails fast so token minting doesn't hang the shell.
Source
Thrown at crates/codegen/xai-grok-shell/src/auth/auth_provider.rs:324
let (out_res, err_res) = tokio::join!(
read_capped(stdout, PROVIDER_STDOUT_CAP_BYTES + 1, &mut out_buf),
read_capped(stderr, PROVIDER_STDERR_CAP_BYTES, &mut err_buf),
);
if let Err(e) = err_res {
tracing::debug!(error = %e, "auth provider: stderr capture failed (advisory)");
}
out_res.map_err(|e| anyhow::anyhow!("reading command stdout: {e}"))?;
child
.wait()
.await
.map_err(|e| anyhow::anyhow!("waiting on command: {e}"))
};
let status = match tokio::time::timeout(timeout, capture).await {
Ok(res) => res?,
Err(_elapsed) => {
let _ = group.kill();
anyhow::bail!("command timed out after {}s", timeout.as_secs());
}
};
if out_buf.len() as u64 > PROVIDER_STDOUT_CAP_BYTES {
anyhow::bail!("command wrote more than {PROVIDER_STDOUT_CAP_BYTES} bytes to stdout");
}
Ok(std::process::Output {
status,
stdout: out_buf,
stderr: err_buf,
})
}
fn resolve_program(command: &str, cwd: Option<&std::path::Path>) -> std::path::PathBuf {
let path = std::path::Path::new(command);
if path.is_absolute() {
return path.to_path_buf();
}
if path.components().count() > 1View on GitHub (pinned to bc7f02eddd)
Solutions
- Run the provider's login/refresh flow manually first so the command no longer prompts
- Ensure the command runs non-interactively (env vars/API keys set, CI mode flags)
- Raise the timeout passed to mint_provider_token if the command is legitimately slow
- Check network reachability of the provider's auth endpoint from this host
Example fix
// before let output = run_capped(&mut cmd, Duration::from_secs(5)).await?; // after let output = run_capped(&mut cmd, Duration::from_secs(30)).await?;
Defensive patterns
Strategy: fallback
Validate before calling
// Pre-check the command can run non-interactively
if which::which("provider-cli").is_err() {
anyhow::bail!("provider CLI not on PATH; login flow would hang/timeout");
} Try / catch
match mint_provider_token(&mut cmd, timeout).await {
Ok(tok) => tok,
Err(e) if e.to_string().contains("timed out") => {
eprintln!("provider command hung; run its login flow interactively first");
return Err(e);
},
Err(e) => return Err(e),
} Prevention
- Always complete interactive provider login before automated use
- Provision credentials via env/API key so no subprocess prompting occurs
- Set timeouts generously but bounded; alert on repeated timeouts
When it happens
Trigger: Calling mint_provider_token (via run_capped) when the configured provider credential command (e.g. a CLI that mints tokens) takes longer than the timeout — tokio::time::timeout fires and the process group is killed.
Common situations: Provider CLI prompting interactively for login on stdin (no TTY available), credential-helper scripts doing slow network calls, DNS hangs, or a mistakenly set very small timeout.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- command wrote more than {PROVIDER_STDOUT_CAP_BYTES} bytes to
- {e} (stderr: {})
- external auth provider `{command}` timed out after 300s
- wait failed: {body}
- git status failed: {}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/e2147e7366f4bd31.
Report an issue: GitHub.