{"record":{"id":"759d6937c316da35","repo":"herdrdev/herdr","slug":"ssh-bridge-stdin-missing","errorCode":null,"errorMessage":"ssh bridge stdin missing","messagePattern":"ssh bridge stdin missing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/remote/attach.rs","lineNumber":1841,"sourceCode":"    _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\n        .arg(\"-T\")\n        .arg(target)\n        .arg(remote_bridge_command(remote_herdr, session_name))\n        .stdin(Stdio::piped())\n        .stdout(Stdio::piped())\n        .stderr(Stdio::inherit());\n\n    let mut child = command\n        .spawn()\n        .map_err(|err| io::Error::new(err.kind(), format!(\"failed to start ssh bridge: {err}\")))?;\n    let mut child_stdin = child\n        .stdin\n        .take()\n        .ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe, \"ssh bridge stdin missing\"))?;\n    let mut child_stdout = child\n        .stdout\n        .take()\n        .ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe, \"ssh bridge stdout missing\"))?;\n    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();","sourceCodeStart":1823,"sourceCodeEnd":1859,"githubUrl":"https://github.com/herdrdev/herdr/blob/f457cff4f2648eee85d176f8a41861241d4e8428/src/remote/attach.rs#L1823-L1859","documentation":"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.","triggerScenarios":"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.","commonSituations":"Rare internal invariant violation; more commonly surfaced when code changes reuse the Child or when platform runtime quirks drop the pipe handle.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match bridge() {\n    Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe && e.to_string().contains(\"stdin missing\") => {\n        bridge() // one retry; pipe setup races are transient\n    }\n    r => r,\n}","preventionTips":["Raise fd limits (ulimit -n) on servers hosting many panes","Retry once on BrokenPipe stdio-missing errors before reporting"],"tags":["ssh","bridge","broken-pipe","stdio","rust"],"backgroundTag":"child-process-stdio-missing","analyzedSha":"f457cff4f2648eee85d176f8a41861241d4e8428","analyzedAt":"2026-08-28T15:41:09.197Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}