herdrdev/herdr · error
ssh install stdin missing
Error message
ssh install stdin missing
What it means
After successfully spawning the ssh install process with stdin piped, install_herdr streams the local Herdr binary into the child's stdin via io::copy; if child.stdin is None at that point, it returns ErrorKind::BrokenPipe 'ssh install stdin missing'. This is a defensive guard for the piped-stdin contract of the spawn.
Source
Thrown at src/remote/attach.rs:511
}
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(())
} else {
Err(command_failed("remote install commit failed", &output))
}
} else {
Err(io::Error::other(format!(
"remote install exited with {status}"
)))View on GitHub (pinned to f457cff4f2)
Solutions
- Confirm the install Command builder sets .stdin(Stdio::piped()) before .spawn()
- Add a unit test asserting the spawned install child always exposes a stdin handle
- If hit at runtime, report it as a bug with the Herdr version and platform
- Check for accidental take() of stdin earlier in the same function
Example fix
// before
let mut child = install_cmd.stdout(Stdio::null()).stderr(Stdio::inherit()).spawn()?;
// after
let mut child = install_cmd.stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::inherit())
.spawn()?; Defensive patterns
Strategy: try-catch
Validate before calling
// Verify the install spawn keeps piped stdin before copying // (builder-level check; nothing runtime-callable by users)
Try / catch
match install_herdr(source, remote) {
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => { /* stdio contract broken; verify version and report bug */ }
other => other?,
} Prevention
- Keep .stdin(Stdio::piped()) in the install spawn builder
- Add tests asserting the spawned install child has a stdin handle
- Report occurrences with Herdr version — this indicates an internal regression
When it happens
Trigger: The ssh install child returned by spawn lacks a stdin handle despite .stdin(Stdio::piped()) being set — a spawn configuration regression or stdio setup failure in install_herdr.
Common situations: Code refactoring that removes or reorders .stdin(Stdio::piped()) in the install spawn builder; essentially a programming error rather than an environmental condition.
Related errors
- ssh bootstrap stdin missing
- failed to start ssh install: {err}
- ssh bridge stdin missing
- ssh bridge stdout missing
- failed to start ssh bridge: {err}
AI-assisted analysis of herdrdev/herdr@f457cff4f2 (2026-08-28).
Data as JSON: /api/errors/ac70c886d19900eb.
Report an issue: GitHub.