xai-org/grok-build · error

process group setup failed: {e}

Error message

process group setup failed: {e}

What it means

After spawning the helper, run_capped creates a process group via xai_grok_tools::util::ProcessGroup::new so the timeout path can kill the whole tree. If group creation fails this error is thrown and the operation aborts.

Source

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

///
/// 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!(
            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)");

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Check system process limits (ulimit -u) and raise if exhausted
  2. Review container/seccomp policy to allow setpgid/setrlimit syscalls
  3. Retry after load subsides if it was a transient resource limit
Defensive patterns

Strategy: try-catch

Try / catch

match mint_provider_token().await {
    Err(e) if e.to_string().contains("process group setup failed") => {
        eprintln!("environment blocks process-group creation: {e}");
        // fall back to a non-grouped execution path or surface to ops
    }
    other => other?,
}

Prevention

When it happens

Trigger: ProcessGroup::new failing — typically setpgid/setsid resource or permission issues, e.g. hitting the process/thread limit (RLIMIT_NPROC) or running in a restricted sandbox that forbids the syscall.

Common situations: Hardened containers/seccomp profiles blocking setpgid, exhausted PID limits under heavy load, or security software blocking process-group creation.

Related errors


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