xai-org/grok-build · error
command failed to start: {e}
Error message
command failed to start: {e} What it means
run_capped spawns a helper auth provider command via tokio::process; if spawn() itself fails the error is wrapped as 'command failed to start'. This happens before any timeout/capture logic.
Source
Thrown at crates/codegen/xai-grok-shell/src/auth/auth_provider.rs:288
/// Spawn `cmd`, capture stdout/stderr with a byte cap (reading both
/// concurrently so a full pipe on one can't deadlock the other; a runaway helper
/// is drained to a sink past the cap so it can't wedge the wait), and bound the
/// whole run by `timeout`. Exceeding the stdout cap is an error.
///
/// On timeout the child's entire process group is killed. The helper is a group
/// leader (`detach_command`'s `setsid`), so a compound `sh -c` helper's
/// grandchildren -- and the `GROK_AUTH_PROVIDER_*` credentials in their env --
/// do not outlive the reported timeout; `kill_on_drop` alone would reap only the
/// direct child.
async fn run_capped(
cmd: &mut tokio::process::Command,
timeout: std::time::Duration,
) -> anyhow::Result<std::process::Output> {
#[allow(clippy::disallowed_methods)] // killed at the timeout this call reports
let mut child = cmd
.spawn()
.map_err(|e| anyhow::anyhow!("command failed to start: {e}"))?;
// Enroll the child's process group so the timeout path can tear down the
// whole tree. Best-effort: if enrollment fails, `kill_on_drop` still reaps
// the direct child.
let mut group = xai_grok_tools::util::ProcessGroup::new()
.map_err(|e| anyhow::anyhow!("process group setup failed: {e}"))?;
if let Err(e) = group.attach(&child) {
tracing::debug!(error = %e, "auth provider: could not enroll helper process group");
}
let stdout = child.stdout.take().expect("stdout is piped");
let stderr = child.stderr.take().expect("stderr is piped");
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!(View on GitHub (pinned to bc7f02eddd)
Solutions
- Verify the helper command exists and is executable: run it manually and check `which <cmd>`
- Fix the configured path/PATH so the binary is found
- If packaged, ensure the helper ships with the build/container image
Example fix
// before provider_cmd = "~/tools/grok-auth-helper"; // not expanded, ENOENT // after provider_cmd = "/usr/local/bin/grok-auth-helper";
Defensive patterns
Strategy: validation
Validate before calling
use std::process::Command;
let ok = Command::new(cmd_path)
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false);
assert!(ok, "auth helper {cmd_path} missing or not executable"); Try / catch
match mint_provider_token().await {
Err(e) if e.to_string().starts_with("command failed to start") => {
eprintln!("auth helper missing: {e}; install it or fix PATH");
}
other => other?,
} Prevention
- Check the helper binary exists at startup (which <cmd> or Path::exists)
- Pin absolute paths in configuration
- Include the helper in container images and install docs
When it happens
Trigger: mint_provider_token invoking a helper binary that does not exist, lacks execute permission, or whose interpreter is missing (ENOENT/EACCES).
Common situations: Provider CLI not installed or not on PATH after an environment change, wrong config path to the helper, missing shebang interpreter, or container images without the helper binary.
Related errors
- git {shown} failed in {}: {}
- {label} exited with {}: {}
- pbcopy exited with status {status}
- {bin} exited with status {status}
- command timed out after {}s
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/4ffdaeea038ef927.
Report an issue: GitHub.