herdrdev/herdr · critical

ssh bridge exited with {status}

Error message

ssh bridge exited with {status}

What it means

After the SSH bridge child exits, a non-successful exit status is wrapped in this ConnectionAborted error. It means the ssh transport process itself terminated abnormally (non-zero exit), breaking the bridged connection.

Source

Thrown at src/remote/attach.rs:1864

    let mut stream_to_child = stream.try_clone()?;
    let mut child_to_stream = stream;

    let upload = thread::spawn(move || {
        let _ = copy_flush(&mut stream_to_child, &mut child_stdin);
    });
    let download = thread::spawn(move || {
        let _ = copy_flush(&mut child_stdout, &mut child_to_stream);
        let _ = crate::ipc::shutdown_local_stream_write(&child_to_stream);
    });

    let status = child.wait()?;
    let _ = upload.join();
    let _ = download.join();

    if status.success() {
        Ok(())
    } else {
        Err(io::Error::new(
            io::ErrorKind::ConnectionAborted,
            format!("ssh bridge exited with {status}"),
        ))
    }
}

#[cfg(windows)]
fn bridge_connection(
    stream: crate::ipc::LocalStream,
    target: &str,
    remote_herdr: &RemoteHerdr,
    session_name: &str,
    ssh_options: Option<&ManagedSshOptions>,
    bridge_stop: &Arc<AtomicBool>,
) -> io::Result<()> {
    let mut command = Command::new("ssh");
    apply_managed_ssh_options(&mut command, ssh_options);
    command

View on GitHub (pinned to f457cff4f2)

Solutions

  1. Run ssh <target> manually to confirm authentication and connectivity work
  2. Check ssh config (~/.ssh/config) for the target, ProxyJump, and identity settings
  3. Look at inherited stderr output from ssh for the actual failure reason
  4. Verify network stability / VPN and retry
  5. Enable SSH keepalives (ServerAliveInterval) for flaky links

Example fix

# reproduce manually to see the real error
ssh user@host herdr server status
Defensive patterns

Strategy: retry

Validate before calling

fn target_reachable(target: &str) -> bool {
    std::process::Command::new("ssh")
        .args([target, "true"])
        .output()
        .map(|o| o.status.success())
        .unwrap_or(false)
}

Try / catch

match bridge() {
    Err(e) if e.kind() == std::io::ErrorKind::ConnectionAborted => {
        if target_reachable(target) { bridge() } else { Err(e) }
    }
    r => r,
}

Prevention

When it happens

Trigger: ssh exits non-zero during the bridge session: authentication failure, network drop, remote command failure, or ssh being killed by a signal — observed after the upload/download copy threads join.

Common situations: SSH key not loaded/agent issues, network interruption, remote herdr socket command failing, ServerAliveInterval killing dead connections, or ssh config errors (bad ProxyJump).

Related errors


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