Hmbown/CodeWhale · error
Failed to run command: {e}
Error message
Failed to run command: {e} What it means
Thrown when std::process::Command::spawn fails while starting the sandboxed child process. The wrapped io::Error is usually NotFound (program not on PATH or bad absolute path), PermissionDenied (file lacks the execute bit, or no interpreter for a script), or a failure resolving exec_env.cwd which is passed to current_dir.
Source
Thrown at crates/tui/src/lib.rs:8931
let (program, args) = command
.split_first()
.ok_or_else(|| anyhow::anyhow!("Command is required"))?;
let spec =
CommandSpec::program(program, args.to_vec(), cwd.clone(), timeout).with_policy(policy);
let manager = SandboxManager::new();
let exec_env = manager.prepare(&spec);
let mut cmd = Command::new(exec_env.program());
cmd.args(exec_env.args())
.current_dir(&exec_env.cwd)
.stdout(Stdio::piped())
.stderr(Stdio::piped());
child_env::apply_to_command(&mut cmd, child_env::string_map_env(&exec_env.env));
let mut child = cmd
.spawn()
.map_err(|e| anyhow::anyhow!("Failed to run command: {e}"))?;
let stdout_handle = child
.stdout
.take()
.ok_or_else(|| anyhow::anyhow!("stdout unavailable"))?;
let stderr_handle = child
.stderr
.take()
.ok_or_else(|| anyhow::anyhow!("stderr unavailable"))?;
let timeout = exec_env.timeout;
let stdout_thread = std::thread::spawn(move || {
let mut reader = stdout_handle;
let mut buf = Vec::new();
let _ = reader.read_to_end(&mut buf);
buf
});
let stderr_thread = std::thread::spawn(move || {
let mut reader = stderr_handle;View on GitHub (pinned to 8880682c63)
Solutions
- Verify the program resolves the same way the sandbox will: run `which <program>` with the child's PATH
- chmod +x the target binary or script, and give interpreted scripts a valid shebang
- Use an absolute path to the program in the sandbox command configuration
- Confirm the cwd passed to the run exists and is a directory (recreate it or pass an absolute cwd)
Example fix
# before: relative script without exec bit sandbox run -- ./tools/lint.sh # after chmod +x /repo/tools/lint.sh sandbox run -- /repo/tools/lint.sh
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: resolve the program before spawning
fn resolvable(program: &str) -> bool {
let p = std::path::Path::new(program);
if p.is_absolute() || p.components().count() > 1 {
p.is_file()
} else {
std::env::var_os("PATH").map_or(false, |paths| {
std::env::split_paths(&paths).any(|dir| dir.join(program).is_file())
})
}
} Try / catch
match cmd.spawn() {
Ok(child) => { /* proceed with pipes and wait */ }
Err(e) if e.kind() == std::io::ErrorKind::NotFound => { /* program missing from PATH: log resolved PATH and cwd */ }
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => { /* chmod +x or fix shebang */ }
Err(e) => return Err(anyhow::anyhow!("Failed to run command: {e}")),
} Prevention
- Prefer absolute program paths in sandbox command configs
- Set exec bits explicitly in CI images and Dockerfiles
- Keep a shebang on interpreted scripts
- Log the PATH and cwd used for the child when spawn fails to speed diagnosis
When it happens
Trigger: Sandbox run with a program name absent from the child environment's PATH, an absolute/relative path whose file is not executable, a script without a shebang line, or a cwd (explicit argument or the current-dir fallback) that was deleted.
Common situations: Typos in tool names inside sandbox configs, PATH shims (nvm, virtualenv) missing from the sanitized child environment, files copied without exec bits (git on FAT, container layers with masked permissions), running from a deleted working directory.
Related errors
- Codewhale terminal receipt sandbox did not match launch
- failed to parse permissions at {}; file contents were omitte
- failed to edit permissions at {}; file contents were omitted
- generated invalid permissions document for {}; file contents
- Codewhale credentials directory must be owned by the current
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/3532e6988b525924.
Report an issue: GitHub.