xai-org/grok-build · error
waiting on command: {e}
Error message
waiting on command: {e} What it means
After capturing output, run_capped awaits child.wait(); an error there is wrapped as 'waiting on command'. It runs under the caller-supplied timeout; the timeout path kills the group separately.
Source
Thrown at crates/codegen/xai-grok-shell/src/auth/auth_provider.rs:317
let mut out_buf = Vec::new();
let mut err_buf = Vec::new();
// One extra stdout byte so an over-cap write is detectable, not truncated.
// The stderr read is advisory (it only feeds the failure log), so only
// stdout governs the mint.
let capture = async {
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,
})
}View on GitHub (pinned to bc7f02eddd)
Solutions
- Remove custom SIGCHLD handlers that reap children behind tokio's back
- Retry the token mint; this is often a one-off race
- If embedding, let tokio own child reaping exclusively
Defensive patterns
Strategy: retry
Try / catch
match mint_provider_token().await {
Err(e) if e.to_string().contains("waiting on command") => {
eprintln!("could not reap helper process: {e}; retrying once");
mint_provider_token().await?;
}
other => other?,
} Prevention
- Do not install custom SIGCHLD handlers when embedding tokio apps
- Let tokio exclusively own child process reaping
- Surface once-only retries for wait races
When it happens
Trigger: tokio's wait() failing to reap the child — e.g. the child was already reaped by an external SIGCHLD handler, or the process handle became invalid.
Common situations: Embedding the library in an app with its own SIGCHLD/sigaction handling that races tokio's reaper, or PID reuse/kill races in restricted environments.
Related errors
- Connection cancelled
- Authentication cancelled
- blocking write task panicked: {e}
- decode task panicked: {e}
- {}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/444dc4a60a5b7df1.
Report an issue: GitHub.