NousResearch/hermes-agent · error · anyhow::Error
spawning {} {:?}: {e}
Error message
spawning {} {:?}: {e} What it means
Raised in run_streamed when tokio Command::spawn fails for a helper program (the message names the program path and args). Spawn failures mean the binary could not be executed at all — not found, not executable, or an OS-level error — before any stdout/stderr streaming begins. On Windows the child is spawned with CREATE_NO_WINDOW so it never flashes a console.
Source
Thrown at apps/bootstrap-installer/src-tauri/src/update.rs:826
cmd.args(args)
.current_dir(cwd)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
for (key, value) in envs {
cmd.env(key, value);
}
#[cfg(target_os = "windows")]
{
use std::os::windows::process::CommandExt;
// CREATE_NO_WINDOW = 0x08000000 — no flashing console behind the GUI.
cmd.creation_flags(0x0800_0000);
}
let mut child = cmd
.spawn()
.map_err(|e| anyhow!("spawning {} {:?}: {e}", program.display(), args))?;
let stdout = child.stdout.take().expect("stdout piped");
let stderr = child.stderr.take().expect("stderr piped");
// Same non-UTF-8-safe decode path as powershell::run_script (#67193).
let mut out = BufReader::new(stdout);
let mut err = BufReader::new(stderr);
let mut out_buf = Vec::new();
let mut err_buf = Vec::new();
let stage_owned = stage.map(|s| s.to_string());
loop {
tokio::select! {
line = read_decoded_line(&mut out, &mut out_buf) => match line {
Ok(Some(l)) => emit_log(app, stage_owned.as_deref(), LogStream::Stdout, &l),
Ok(None) => break,
Err(e) => { tracing::warn!("stdout read error: {e}"); break; }
},
line = read_decoded_line(&mut err, &mut err_buf) => match line {View on GitHub (pinned to c896c09c42)
Solutions
- Run the exact command printed in the message ({program} {args}) from a shell to see the OS error directly.
- Fix the target: reinstall via the bootstrap installer if the shim/binary is missing or not executable (chmod +x on Unix).
- Check architecture match of the binary vs the machine if you get an exec format error.
- Restore the binary if antivirus quarantined it and exempt the install root.
Defensive patterns
Strategy: validation
Validate before calling
use std::os::unix::fs::PermissionsExt;
fn spawnable(path: &std::path::Path) -> bool {
match std::fs::metadata(path) {
Ok(m) => m.is_file() && (!cfg!(unix) || m.permissions().mode() & 0o111 != 0),
Err(_) => false,
}
}
if !spawnable(&hermes) {
eprintln!("{} is missing or not executable — repair the install.", hermes.display());
} Try / catch
match cmd.spawn() {
Ok(child) => child,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
// missing binary: repairable — point at re-running the installer
return Err(anyhow!("{} not found — re-run the installer to repair", program.display()));
}
Err(e) => return Err(anyhow!("spawning {} {:?}: {e}", program.display(), args)),
} Prevention
- Check the target binary exists and is executable before spawning.
- Don't move installs between architectures or volumes with venvs — venv shims break.
- Exempt the install root from antivirus quarantine so spawned binaries don't vanish.
When it happens
Trigger: hermes shim path from [546] missing or lacking +x on Unix; spawning a .bat/.cmd on Windows where the extension or cmd /c handling matters; PATH-dependent program resolution failing because the updater's env is minimal; exec format error from a truncated/ARM-vs-x86 binary.
Common situations: The venv shim exists but its interpreter symlink is broken; a copied install between Intel and Apple Silicon macs; antivirus quarantined the target binary; a script without a shebang spawned directly on Unix.
Related errors
- hermes update failed (exit {:?}). See {} for details.
- waiting for child: {e}
- running ditto: {e}
- install script invocation failed: {e:#}
- Another Hermes update is already running (PID {}, started {}
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/9267ce9fe5634c55.
Report an issue: GitHub.