herdrdev/herdr · error
ssh bridge stdin missing
Error message
ssh bridge stdin missing
What it means
The SSH bridge child was spawned with Stdio::piped() for stdin, but child.stdin was None when taken. This BrokenPipe error indicates the child's stdin handle was already consumed or unavailable, so bridging cannot upload data to ssh.
Source
Thrown at src/remote/attach.rs:1841
_bridge_stop: &Arc<AtomicBool>,
) -> io::Result<()> {
let mut command = Command::new("ssh");
apply_managed_ssh_options(&mut command, ssh_options);
command
.arg("-T")
.arg(target)
.arg(remote_bridge_command(remote_herdr, session_name))
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit());
let mut child = command
.spawn()
.map_err(|err| io::Error::new(err.kind(), format!("failed to start ssh bridge: {err}")))?;
let mut child_stdin = child
.stdin
.take()
.ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe, "ssh bridge stdin missing"))?;
let mut child_stdout = child
.stdout
.take()
.ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe, "ssh bridge stdout missing"))?;
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();View on GitHub (pinned to f457cff4f2)
Solutions
- Retry the attach — transient pipe setup failures can occur under fd exhaustion
- Check for fd/resource limits (ulimit -n) that may cause pipe creation to silently degrade
- Report as a bug if it reproduces consistently, since spawn was configured with piped stdin
Defensive patterns
Strategy: retry
Try / catch
match bridge() {
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe && e.to_string().contains("stdin missing") => {
bridge() // one retry; pipe setup races are transient
}
r => r,
} Prevention
- Raise fd limits (ulimit -n) on servers hosting many panes
- Retry once on BrokenPipe stdio-missing errors before reporting
When it happens
Trigger: Immediately after a successful spawn, taking .stdin on the Child returns None — typically only possible if the handle was taken twice or the Child was constructed without piped stdin; in practice this guards against internal API misuse or race in bridge setup.
Common situations: Rare internal invariant violation; more commonly surfaced when code changes reuse the Child or when platform runtime quirks drop the pipe handle.
Related errors
- ssh bridge stdout missing
- ssh bootstrap stdin missing
- ssh install stdin missing
- failed to start ssh bridge: {err}
- ssh bridge exited with {status}
AI-assisted analysis of herdrdev/herdr@f457cff4f2 (2026-08-28).
Data as JSON: /api/errors/759d6937c316da35.
Report an issue: GitHub.