xai-org/grok-build · error

failed to exec {program}: {err}

Error message

failed to exec {program}: {err}

What it means

On Unix, `exec_command` uses `std::os::unix::process::CommandExt::exec`, which replaces the current process and only ever returns if the program could not be executed (not found, permission denied, exec format error). The library wraps that errno error in an anyhow error naming the program. It means the wrapper could not hand off to the target binary at all.

Source

Thrown at crates/codegen/xai-grok-pager/src/wrap_cmd.rs:199

    if !cfg!(any(unix, windows)) {
        return false;
    }

    use std::io::IsTerminal;
    std::io::stdin().is_terminal()
        && std::io::stdout().is_terminal()
        && std::io::stderr().is_terminal()
}

/// Replace the current process with `program <args...>` (no PTY wrapping).
#[cfg(unix)]
fn exec_command(program: &str, args: &[String]) -> Result<()> {
    use std::os::unix::process::CommandExt;

    let err = std::process::Command::new(program).args(args).exec();

    // exec() only returns on error.
    Err(anyhow::anyhow!("failed to exec {program}: {err}"))
}

/// On non-Unix platforms, spawn and wait.
#[cfg(not(unix))]
fn exec_command(program: &str, args: &[String]) -> Result<()> {
    let status = std::process::Command::new(program)
        .args(args)
        .status()
        .map_err(|e| anyhow::anyhow!("failed to run {program}: {e}"))?;

    std::process::exit(status.code().unwrap_or(1));
}

#[cfg(all(test, unix))]
#[path = "wrap_cmd_tests.rs"]
mod tests;

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Run `which <program>` in the same environment to confirm the binary resolves on PATH.
  2. Check the execute permission bit (`ls -l`, `chmod +x`) on the target binary.
  3. Verify the binary matches the platform architecture (`file <program>`).
  4. If invoked with a relative path, use an absolute path or resolve it programmatically before exec.
  5. Inspect the inner errno in `{err}` (NotFound vs PermissionDenied vs ExecFormatError) to pinpoint the cause.

Example fix

// before
exec_command("grok-sandboxed-tool", &args)?; // relies on PATH inside sandbox
// after
let program = which::which("grok-sandboxed-tool")
    .map_err(|_| anyhow::anyhow!("grok-sandboxed-tool not found on PATH"))?
    .to_string_lossy().to_string();
exec_command(&program, &args)?;
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;
fn can_exec(program: &str) -> Result<(), String> {
    if program.contains('/') {
        let p = Path::new(program);
        if !p.exists() { return Err(format!("{program} does not exist")); }
        return std::fs::metadata(p)
            .map(|m| m.permissions().mode() & 0o111 != 0)
            .map_err(|e| e.to_string())
            .and_then(|x| if x { Ok(()) } else { Err(format!("{program} not executable")) });
    }
    let path = std::env::var("PATH").unwrap_or_default();
    for dir in path.split(':') {
        let candidate = Path::new(dir).join(program);
        if candidate.is_file() { return Ok(()); }
    }
    Err(format!("{program} not found on PATH"))
}

Try / catch

if let Err(e) = exec_command(program, &args) {
    let msg = e.to_string();
    if msg.contains("No such file") {
        eprintln!("program '{program}' not found; check PATH");
    } else if msg.contains("Permission denied") {
        eprintln!("program '{program}' is not executable; chmod +x");
    } else {
        eprintln!("exec failed: {e:#}");
    }
    std::process::exit(127);
}

Prevention

When it happens

Trigger: The wrapped program name does not exist on PATH; the file exists but lacks the execute bit; the binary is for a different architecture (ENOEXEC); a shebang points at a missing interpreter.

Common situations: PATH altered inside a sandboxed wrapper so the target binary is invisible; user moved/renamed the tool the wrapper delegates to; running a macOS binary on Linux; node_modules bin scripts losing +x after a bad copy.

Related errors


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