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

  1. Run the exact command printed in the message ({program} {args}) from a shell to see the OS error directly.
  2. Fix the target: reinstall via the bootstrap installer if the shim/binary is missing or not executable (chmod +x on Unix).
  3. Check architecture match of the binary vs the machine if you get an exec format error.
  4. 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

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


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/9267ce9fe5634c55. Report an issue: GitHub.