herdrdev/herdr · error
remote client exited with {status}
Error message
remote client exited with {status} What it means
The spawned remote client process (e.g. an SSH-attached herdr client) exited with a non-success status code. The wrapper rethrows it as io::ErrorKind::Interrupted with the process's ExitStatus formatted into the message. It means the remote side of an attach session terminated abnormally.
Source
Thrown at src/remote/attach.rs:2138
let status = Command::new(exe)
.arg("client")
.env(
crate::server::socket_paths::CLIENT_SOCKET_PATH_ENV_VAR,
local_socket,
)
.env("HERDR_RENDER_ENCODING", "terminal-ansi")
.env(REATTACH_COMMAND_ENV_VAR, reattach_command)
.env(REMOTE_KEYBINDINGS_ENV_VAR, keybindings.as_str())
.env_remove(crate::api::SOCKET_PATH_ENV_VAR)
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()?;
if status.success() {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::Interrupted,
format!("remote client exited with {status}"),
))
}
}
fn local_forward_socket_path(target: &str, session_name: &str) -> PathBuf {
let pid = std::process::id();
let target_clean = sanitize_path_component(target);
let session_clean = sanitize_path_component(session_name);
let readable_name = format!("herdr-remote-{pid}-{target_clean}-{session_clean}.sock");
let target_prefix: String = target_clean.chars().take(8).collect();
let hash = short_socket_hash(target, session_name);
let short_name = format!("herdr-r-{pid}-{target_prefix}-{hash}.sock");
crate::platform::remote_bridge_endpoint_path(&readable_name, &short_name)
}
#[cfg(all(test, unix))]View on GitHub (pinned to f457cff4f2)
Solutions
- Check the child's exit status in the message (exit code vs signal) to identify crash vs clean nonzero exit
- Run the remote client command manually over ssh to see its stderr
- Verify the remote herdr binary exists and is a compatible version
- Check network/SSH stability if the status indicates signal termination (e.g. SIGKILL/SIGTERM)
Defensive patterns
Strategy: try-catch
Try / catch
match attach_result { Ok(()) => {}, Err(e) if e.kind() == io::ErrorKind::Interrupted && e.to_string().contains("remote client exited") => { tracing::warn!("remote attach ended: {e}"); }, Err(e) => return Err(e) } Prevention
- Treat remote client exit as an expected detach, not a fatal error
- Log the child's stderr (inherited) for post-mortem
- Keep SSH keepalives configured for long remote sessions
When it happens
Trigger: Calling the remote attach helper that spawns a child herdr client with inherited stdio and checking status.success(); any nonzero exit code or signal termination of that child produces this error.
Common situations: SSH connection dropped mid-session, remote herdr binary missing or crashing, remote shell exiting due to auth failure, or the remote client hitting its own fatal error.
Related errors
- failed to create private herdr ssh config directory
- failed to create private herdr ssh config directory
- SSH control socket path exceeds the Unix socket length limit
- failed to create private herdr ssh config directory
- ssh bootstrap stdin missing
AI-assisted analysis of herdrdev/herdr@f457cff4f2 (2026-08-28).
Data as JSON: /api/errors/3ccc9d19a231201a.
Report an issue: GitHub.