{"record":{"id":"1cb48d4f81df1671","repo":"Hmbown/CodeWhale","slug":"failed-to-capture-stdout","errorCode":null,"errorMessage":"Failed to capture stdout","messagePattern":"Failed to capture stdout","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/shell.rs","lineNumber":2716,"sourceCode":"            {\n                windows_job = attach_windows_job(&child, original_command);\n            }\n\n            let stdin_handle = child.stdin.take().map(StdinWriter::Pipe);\n\n            let (stdout_thread, stderr_thread) =\n                if let (Some(reader), Some(output)) = (combined_reader, bounded_output.as_ref()) {\n                    (\n                        Some(spawn_bounded_reader_thread(reader, Arc::clone(output))),\n                        None,\n                    )\n                } else {\n                    let stdout_handle = child.stdout.take().ok_or_else(|| {\n                        #[cfg(windows)]\n                        terminate_unregistered_process(&mut child, windows_job.as_ref());\n                        #[cfg(not(windows))]\n                        terminate_unregistered_process(&mut child);\n                        anyhow!(\"Failed to capture stdout\")\n                    })?;\n                    let stderr_handle = child.stderr.take().ok_or_else(|| {\n                        #[cfg(windows)]\n                        terminate_unregistered_process(&mut child, windows_job.as_ref());\n                        #[cfg(not(windows))]\n                        terminate_unregistered_process(&mut child);\n                        anyhow!(\"Failed to capture stderr\")\n                    })?;\n                    (\n                        Some(spawn_reader_thread(\n                            stdout_handle,\n                            Arc::clone(&stdout_buffer),\n                        )),\n                        stderr_buffer\n                            .as_ref()\n                            .map(|buffer| spawn_reader_thread(stderr_handle, Arc::clone(buffer))),\n                    )\n                };","sourceCodeStart":2698,"sourceCodeEnd":2734,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/shell.rs#L2698-L2734","documentation":"When the tool spawns a child on the foreground path without a TTY, it takes the child's stdout handle to feed a reader thread. If `child.stdout` is None (the OS failed to give the process a stdout pipe, or it was already consumed), the tool cannot proceed: it terminates the just-spawned (unregistered) child and returns this error. It signals a broken pipe wiring between the parent and the spawned process rather than a problem with the command itself.","triggerScenarios":"Spawning a synchronous sandboxed/non-TTY command whose `Child::stdout` is unexpectedly None after spawn — e.g. the OS denies pipe creation, resource exhaustion (fd limits), or a platform-level spawn quirk on Windows/Unix.","commonSituations":"Systems at or near the file-descriptor limit so pipe creation fails; sandbox/job-object setups interfering with stdio inheritance; resource-constrained containers.","solutions":["Check and raise the file-descriptor limit (ulimit -n) and retry — pipe creation failures usually come from fd exhaustion","Re-run the command; transient pipe-setup failures may not recur","Verify the sandbox/job configuration isn't stripping stdio from the child","If reproducible, report/inspect how the child is spawned (std::process Command stdio wiring) for a platform bug"],"exampleFix":"// caller-side mitigation: run with a bounded fd budget and retry\n// before\nshell.run(\"make\", { \"background\": false })\n// after: raise fd limit first, then retry the same call\n// (ulimit -n 4096) then retry the same call","handlingStrategy":"retry","validationCode":"// check fd headroom before spawning many processes\nlet ok = unsafe { libc::getrlimit(libc::RLIMIT_NOFILE) };\n// ensure soft limit leaves room for pipes; raise ulimit -n if near the cap","typeGuard":null,"tryCatchPattern":"// treat it as transient spawn failure\nmatch result {\n    Err(e) if e.to_string().contains(\"Failed to capture stdout\") => retry_with_backoff(cmd, 2),\n    other => other,\n}","preventionTips":["Keep the fd limit generous on systems running many concurrent shells","Avoid leaking descriptors in long-lived agent sessions","Review sandbox/job-object settings so children inherit stdio pipes"],"tags":["shell","process-spawn","stdout","pipe"],"backgroundTag":"broken-pipe","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}