Hmbown/CodeWhale · error
Failed to run command
Error message
Failed to run command: {e} What it means
This error wraps a failed `Command::spawn()` when the TUI launches an external child process with piped stdout/stderr. `spawn()` only fails at exec/startup time — the binary could not be found, permissions were denied, or the OS refused to fork. The message embeds the underlying OS error via anyhow.
Solutions
- Check the wrapped OS error text: 'No such file or directory' means the binary path/name is wrong
- Use an absolute path to the binary instead of relying on PATH
- Verify the file exists and is executable (`which <cmd>`, `chmod +x`)
- If child_env::apply_to_command overrides env, confirm PATH is preserved
Example fix
// before
let mut child = cmd.spawn().map_err(|e| anyhow::anyhow!("Failed to run command: {e}"))?;
// after
let program = which::which(&program).map_err(|e| anyhow::anyhow!("command `{program}` not found: {e}"))?;
let mut child = cmd.spawn().map_err(|e| anyhow::anyhow!("Failed to run command `{program}`: {e}"))?; Defensive patterns
Strategy: try-catch
Validate before calling
const path = whichSync(cmd);
if (!fs.existsSync(path) || !(fs.statSync(path).mode & 0o111)) throw new Error(`${cmd} not executable`); Type guard
fn is_spawnable(cmd: &str) -> bool {
which::which(cmd).map(|p| p.is_file()).unwrap_or(false)
} Try / catch
match cmd.spawn() {
Ok(child) => child,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
eprintln!("command not found: {}", program); return;
}
Err(e) => return Err(anyhow::anyhow!("Failed to run command: {e}")),
} Prevention
- Resolve commands to absolute paths at startup and fail fast if missing
- Never strip PATH from child env without substituting it
- Check executable permission when configuring tools
When it happens
Trigger: Any code path that runs an external command through this helper (e.g. an exec tool) when the program path does not exist, is not executable, or the process cannot be forked.
Common situations: Command name not on PATH or misspelled; binary built for wrong platform; missing execute permission; environment stripping PATH so bare names don't resolve; resource limits preventing fork.
Related errors
- exited
- git failed
- tmux new-session failed with
- Cannot resolve current binary path
- Cloud agent harness exited with code
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/3532e6988b525924.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/lib.rs:10553
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 73e0f67d83)