xai-org/grok-build · error · std::io::Error
spawn shell in {}: {e}
Error message
spawn shell in {}: {e} What it means
When spawning a shell process via Command::spawn fails, the raw io::Error is wrapped with the working directory for context: "spawn shell in {cwd}: {e}". On Unix the process is also attached to a new ProcessGroup, so the error means the shell binary could not be launched (or setup failed) before any session existed.
Source
Thrown at crates/codegen/xai-grok-tools/src/computer/local/terminal.rs:3258
crate::util::apply_grok_agent_marker(&mut cmd);
// Flags set inline: tokio's creation_flags is a SET, not OR, so the detach
// helpers don't compose. CREATE_BREAKAWAY_FROM_JOB fails with os error 5 when
// the parent's job lacks JOB_OBJECT_LIMIT_BREAKAWAY_OK; the caller retries without it.
let mut flags = CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP;
if with_breakaway {
flags |= CREATE_BREAKAWAY_FROM_JOB;
}
cmd.creation_flags(flags.0);
cmd
};
#[cfg(unix)]
let mut group = crate::util::ProcessGroup::new()?;
#[cfg(unix)]
#[allow(clippy::disallowed_methods)] // attached to the process group built above
let child = cmd.spawn().map_err(|e| {
std::io::Error::new(e.kind(), format!("spawn shell in {}: {e}", cwd.display()))
})?;
#[cfg(not(unix))]
#[allow(clippy::disallowed_methods)] // attached to the process group built in this block
let (child, mut group) = {
let group = crate::util::ProcessGroup::new()?;
let mut cmd = build_cmd(true);
match cmd.spawn() {
Ok(child) => (child, group),
Err(e) if e.raw_os_error() == Some(5) => {
// Job disallows breakaway: retry without the flag. attach() below
// will also fail, but kill_on_drop still reaps the immediate child.
tracing::debug!(
"spawn with CREATE_BREAKAWAY_FROM_JOB returned ERROR_ACCESS_DENIED; \
retrying without breakaway (process-tree teardown disabled for this child)"
);
drop(cmd);
let mut cmd = build_cmd(false);View on GitHub (pinned to bc7f02eddd)
Solutions
- Check the error's inner kind/message and verify the shell binary exists and is executable (e.g. ls -l $(which bash)).
- Ensure the cwd passed to the spawn exists and is accessible; create it before spawning.
- Check process/thread limits (ulimit -u, container pids limit) if the cause is EAGAIN/EAGAIN-like resource exhaustion.
- Log and surface e.kind() to distinguish NotFound vs PermissionDenied vs Other.
Example fix
// before
let child = cmd.spawn().map_err(...)?;
// after
std::fs::create_dir_all(cwd)?;
let child = cmd.spawn().map_err(|e| {
std::io::Error::new(e.kind(), format!("spawn shell in {}: {e}", cwd.display()))
})?; Defensive patterns
Strategy: validation
Validate before calling
let shell = resolve_shell(); // e.g. /bin/bash
debug_assert!(std::path::Path::new(&shell).exists());
std::fs::create_dir_all(cwd)?;
if !cwd.is_dir() { return Err(anyhow!("cwd {:?} is not a directory", cwd)); } Try / catch
match spawn_shell(cwd) {
Ok(child) => child,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
bail!("shell binary missing on this image; install bash or fix config")
}
Err(e) => return Err(e.into()),
} Prevention
- Verify the configured shell exists in the deployment image at startup.
- Always create the session cwd before spawning.
- Check container pids limits (ulimit -u, pids.max) when spawning many sessions.
- Preserve e.kind() when wrapping spawn errors for easier triage.
When it happens
Trigger: spawn returning Err — typically because the shell executable does not exist or lacks execute permission, cwd does not exist, fork/exec limits (EAGAIN) are hit, or resource limits (RLIMIT_NPROC) prevent process creation.
Common situations: Configured shell path wrong (e.g. /bin/zsh absent on the image); session cwd deleted or never created; running in a container with a low process limit; permission errors after restrictive chmod on the binary.
Related errors
- failed to spawn {bin}: {e}
- failed to run {bin}: {e}
- Failed to capture ripgrep stdout
- unix socket path too long: {}
- unmount {}: {err}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/5171437d24e9f95c.
Report an issue: GitHub.