{"record":{"id":"2e81b892aea6cbf5","repo":"herdrdev/herdr","slug":"ssh-bridge-stdout-missing","errorCode":null,"errorMessage":"ssh bridge stdout missing","messagePattern":"ssh bridge stdout missing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/remote/attach.rs","lineNumber":1845,"sourceCode":"    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();\n\n    if status.success() {\n        Ok(())\n    } else {","sourceCodeStart":1827,"sourceCodeEnd":1863,"githubUrl":"https://github.com/herdrdev/herdr/blob/f457cff4f2648eee85d176f8a41861241d4e8428/src/remote/attach.rs#L1827-L1863","documentation":"The SSH bridge child was spawned with Stdio::piped() for stdout, but child.stdout was None when taken. This BrokenPipe error means herdr cannot read output from the ssh process, so the bridge cannot relay data back from the remote.","triggerScenarios":"Taking .stdout on the freshly spawned bridge Child returns None — an internal invariant failure in bridge setup, or fd exhaustion interfering with pipe handles.","commonSituations":"Extremely rare; usually fd limit pressure or a regression in bridge construction. Distinct from network failures, which occur later during copy loops.","solutions":["Retry the attach operation","Raise file descriptor limits (ulimit -n 4096) if running under a constrained shell","Report reproducible occurrences upstream with logs"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = bridge() {\n    if e.kind() == std::io::ErrorKind::BrokenPipe {\n        return bridge(); // retry transient handle loss\n    }\n    return Err(e);\n}","preventionTips":["Avoid fd exhaustion; monitor open-handle counts","Treat early BrokenPipe bridge errors as retryable"],"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"}