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

  1. Remove custom SIGCHLD handlers that reap children behind tokio's back
  2. Retry the token mint; this is often a one-off race
  3. 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

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


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/444dc4a60a5b7df1. Report an issue: GitHub.