xai-org/grok-build · error

reading command stdout: {e}

Error message

reading command stdout: {e}

What it means

run_capped reads the helper's stdout with read_capped (with a byte cap). If the stdout read future returns an error it is surfaced as 'reading command stdout'. Stderr read failures are only advisory and logged, not fatal.

Source

Thrown at crates/codegen/xai-grok-shell/src/auth/auth_provider.rs:313

        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!(
            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,

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Check whether the helper process died unexpectedly (dmesg/oom logs, exit signals)
  2. Re-run mint_provider_token to see if it is transient
  3. Ensure the helper writes bounded output; oversized output is capped, but corrupt pipes indicate helper misbehavior
Defensive patterns

Strategy: retry

Try / catch

match mint_provider_token().await {
    Err(e) if e.to_string().contains("reading command stdout") => {
        eprintln!("helper died mid-run: {e}; check oom/kill logs, retrying once");
        mint_provider_token().await?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: The pipe to the helper's stdout breaking (helper killed the reader side), an IO error on the pipe, or read_capped failing internally during capture.

Common situations: Helper process being killed by OOM-killer or security policy mid-run, pipe buffer misuse in a forked helper, or disk/IO errors in exotic setups.

Related errors


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