{"record":{"id":"5171437d24e9f95c","repo":"xai-org/grok-build","slug":"spawn-shell-in-e","errorCode":null,"errorMessage":"spawn shell in {}: {e}","messagePattern":"spawn shell in (.+?): (.+?)","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-tools/src/computer/local/terminal.rs","lineNumber":3258,"sourceCode":"        crate::util::apply_grok_agent_marker(&mut cmd);\n\n        // Flags set inline: tokio's creation_flags is a SET, not OR, so the detach\n        // helpers don't compose. CREATE_BREAKAWAY_FROM_JOB fails with os error 5 when\n        // the parent's job lacks JOB_OBJECT_LIMIT_BREAKAWAY_OK; the caller retries without it.\n        let mut flags = CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP;\n        if with_breakaway {\n            flags |= CREATE_BREAKAWAY_FROM_JOB;\n        }\n        cmd.creation_flags(flags.0);\n        cmd\n    };\n\n    #[cfg(unix)]\n    let mut group = crate::util::ProcessGroup::new()?;\n    #[cfg(unix)]\n    #[allow(clippy::disallowed_methods)] // attached to the process group built above\n    let child = cmd.spawn().map_err(|e| {\n        std::io::Error::new(e.kind(), format!(\"spawn shell in {}: {e}\", cwd.display()))\n    })?;\n\n    #[cfg(not(unix))]\n    #[allow(clippy::disallowed_methods)] // attached to the process group built in this block\n    let (child, mut group) = {\n        let group = crate::util::ProcessGroup::new()?;\n        let mut cmd = build_cmd(true);\n        match cmd.spawn() {\n            Ok(child) => (child, group),\n            Err(e) if e.raw_os_error() == Some(5) => {\n                // Job disallows breakaway: retry without the flag. attach() below\n                // will also fail, but kill_on_drop still reaps the immediate child.\n                tracing::debug!(\n                    \"spawn with CREATE_BREAKAWAY_FROM_JOB returned ERROR_ACCESS_DENIED; \\\n                     retrying without breakaway (process-tree teardown disabled for this child)\"\n                );\n                drop(cmd);\n                let mut cmd = build_cmd(false);","sourceCodeStart":3240,"sourceCodeEnd":3276,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-tools/src/computer/local/terminal.rs#L3240-L3276","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet child = cmd.spawn().map_err(...)?;\n// after\nstd::fs::create_dir_all(cwd)?;\nlet child = cmd.spawn().map_err(|e| {\n    std::io::Error::new(e.kind(), format!(\"spawn shell in {}: {e}\", cwd.display()))\n})?;","handlingStrategy":"validation","validationCode":"let shell = resolve_shell(); // e.g. /bin/bash\ndebug_assert!(std::path::Path::new(&shell).exists());\nstd::fs::create_dir_all(cwd)?;\nif !cwd.is_dir() { return Err(anyhow!(\"cwd {:?} is not a directory\", cwd)); }","typeGuard":null,"tryCatchPattern":"match spawn_shell(cwd) {\n    Ok(child) => child,\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {\n        bail!(\"shell binary missing on this image; install bash or fix config\")\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["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."],"tags":["process-spawn","shell","io","linux"],"backgroundTag":"process-spawn-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}