herdrdev/herdr · error

failed to start ssh install: {err}

Error message

failed to start ssh install: {err}

What it means

install_herdr spawns the remote install command (an ssh invocation streaming the binary into a remote tar/cat pipeline) with stdin piped; if the ssh process cannot be spawned, the os error is wrapped with the context 'failed to start ssh install: {err}' preserving the original ErrorKind. This is the first failure point of remote binary installation.

Source

Thrown at src/remote/attach.rs:504

        self.command().arg(command).output()
    }

    fn install_herdr(&self, remote_herdr: &RemoteHerdr, source_path: &Path) -> io::Result<()> {
        let output = self.sh_output(&remote_install_prepare_script(remote_herdr))?;
        if !output.status.success() {
            return Err(command_failed("remote install preparation failed", &output));
        }
        let (tmp_path, dest_path) = parse_remote_install_paths(&output.stdout)?;

        let mut child = self
            .command()
            .arg(remote_install_stream_command(&tmp_path))
            .stdin(Stdio::piped())
            .stdout(Stdio::null())
            .stderr(Stdio::inherit())
            .spawn()
            .map_err(|err| {
                io::Error::new(err.kind(), format!("failed to start ssh install: {err}"))
            })?;

        let mut source = File::open(source_path)?;
        let copy_result = if let Some(mut stdin) = child.stdin.take() {
            io::copy(&mut source, &mut stdin).map(|_| ())
        } else {
            Err(io::Error::new(
                io::ErrorKind::BrokenPipe,
                "ssh install stdin missing",
            ))
        };
        let status = child.wait()?;
        copy_result?;

        if status.success() {
            let output = self.sh_output(&remote_install_commit_script(&tmp_path, &dest_path))?;
            if output.status.success() {
                Ok(())

View on GitHub (pinned to f457cff4f2)

Solutions

  1. Verify ssh is installed and on PATH: run `which ssh` in the same environment Herdr runs in
  2. Install an OpenSSH client (e.g. openssh-client package) if missing
  3. If launching from a GUI/service, ensure PATH includes the ssh binary or configure an absolute path
  4. Inspect the wrapped err (kind/message) to distinguish NotFound vs PermissionDenied and fix accordingly

Example fix

# before
$ herdr remote attach host
Error: failed to start ssh install: No such file or directory (os error 2)

# after
$ sudo apt-get install openssh-client
$ herdr remote attach host
Defensive patterns

Strategy: validation

Validate before calling

// Before calling prepare_remote_herdr/install_herdr
if which::which("ssh").is_err() { return Err("ssh client not found on PATH"); }

Try / catch

match install_herdr(...) {
    Err(e) if e.to_string().contains("failed to start ssh install") && e.kind() == std::io::ErrorKind::NotFound => { /* install openssh-client and retry */ }
    other => other?,
}

Prevention

When it happens

Trigger: Calling install_herdr when the ssh binary is missing from PATH (NotFound), lacks execute permission (PermissionDenied), or the Command construction fails at spawn time on the local machine.

Common situations: Minimal/container environments without an ssh client installed, PATH misconfiguration in GUI-launched apps, ssh not installed on a fresh machine, or an incorrect ssh binary path override.

Related errors


AI-assisted analysis of herdrdev/herdr@f457cff4f2 (2026-08-28). Data as JSON: /api/errors/91e4579bf974b095. Report an issue: GitHub.