{"record":{"id":"8328468d02547e8b","repo":"herdrdev/herdr","slug":"ssh-bridge-exited-with-status","errorCode":null,"errorMessage":"ssh bridge exited with {status}","messagePattern":"ssh bridge exited with (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/remote/attach.rs","lineNumber":1864,"sourceCode":"    let mut stream_to_child = stream.try_clone()?;\n    let mut child_to_stream = stream;\n\n    let upload = thread::spawn(move || {\n        let _ = copy_flush(&mut stream_to_child, &mut child_stdin);\n    });\n    let download = thread::spawn(move || {\n        let _ = copy_flush(&mut child_stdout, &mut child_to_stream);\n        let _ = crate::ipc::shutdown_local_stream_write(&child_to_stream);\n    });\n\n    let status = child.wait()?;\n    let _ = upload.join();\n    let _ = download.join();\n\n    if status.success() {\n        Ok(())\n    } else {\n        Err(io::Error::new(\n            io::ErrorKind::ConnectionAborted,\n            format!(\"ssh bridge exited with {status}\"),\n        ))\n    }\n}\n\n#[cfg(windows)]\nfn bridge_connection(\n    stream: crate::ipc::LocalStream,\n    target: &str,\n    remote_herdr: &RemoteHerdr,\n    session_name: &str,\n    ssh_options: Option<&ManagedSshOptions>,\n    bridge_stop: &Arc<AtomicBool>,\n) -> io::Result<()> {\n    let mut command = Command::new(\"ssh\");\n    apply_managed_ssh_options(&mut command, ssh_options);\n    command","sourceCodeStart":1846,"sourceCodeEnd":1882,"githubUrl":"https://github.com/herdrdev/herdr/blob/f457cff4f2648eee85d176f8a41861241d4e8428/src/remote/attach.rs#L1846-L1882","documentation":"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.","triggerScenarios":"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.","commonSituations":"SSH key not loaded/agent issues, network interruption, remote herdr socket command failing, ServerAliveInterval killing dead connections, or ssh config errors (bad ProxyJump).","solutions":["Run ssh <target> manually to confirm authentication and connectivity work","Check ssh config (~/.ssh/config) for the target, ProxyJump, and identity settings","Look at inherited stderr output from ssh for the actual failure reason","Verify network stability / VPN and retry","Enable SSH keepalives (ServerAliveInterval) for flaky links"],"exampleFix":"# reproduce manually to see the real error\nssh user@host herdr server status","handlingStrategy":"retry","validationCode":"fn target_reachable(target: &str) -> bool {\n    std::process::Command::new(\"ssh\")\n        .args([target, \"true\"])\n        .output()\n        .map(|o| o.status.success())\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match bridge() {\n    Err(e) if e.kind() == std::io::ErrorKind::ConnectionAborted => {\n        if target_reachable(target) { bridge() } else { Err(e) }\n    }\n    r => r,\n}","preventionTips":["Test manual ssh connectivity to the target before attaching","Configure ServerAliveInterval/CountMax for flaky networks","Capture ssh stderr (inherited) to diagnose exit reasons"],"tags":["ssh","bridge","connection-aborted","exit-status","rust"],"backgroundTag":"ssh-connection-failed","analyzedSha":"f457cff4f2648eee85d176f8a41861241d4e8428","analyzedAt":"2026-08-28T15:41:09.197Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}