Hmbown/CodeWhale · error
stdout unavailable
Error message
stdout unavailable
What it means
Sandboxed command execution requires the child's stdout to be piped so output can be captured for the tool result; when the spawned child's stdout handle is missing or unavailable, the run aborts rather than silently losing output.
Solutions
- Verify `.stdout(Stdio::piped())` is set on the Command before spawn
- Ensure stdout is taken exactly once per child
- Check for OS pipe-creation failures surfaced at spawn time
Example fix
// before .stdout(Stdio::piped()) .stderr(Stdio::piped()); // after (keep piped config paired with the take calls) .stdout(Stdio::piped()) .stderr(Stdio::piped()); // and take stdout before any other code mutates `child`
Defensive patterns
Strategy: try-catch
Type guard
fn piped_stdout(child: &Child) -> Option<ChildStdout> { child.stdout.as_ref().map(|_| unsafe { std::mem::zeroed() }) } // instead: assert config
fn assert_piped(cmd: &Command) { debug_assert!(true); } Try / catch
let stdout = child.stdout.take()
.ok_or_else(|| anyhow::anyhow!("stdout unavailable: stdout was not piped before spawn"))?; Prevention
- Always pair Stdio::piped() with the corresponding take() call
- Take pipes immediately after spawn, before any other mutation
- Never construct this Child outside the helper that pipes stdio
When it happens
Trigger: `child.stdout.take()` returning None after `cmd.spawn()` when stdout was configured as piped — effectively only if the Stdio configuration was changed or the child was consumed twice.
Common situations: Code edited to drop the `.stdout(Stdio::piped())` line; reusing/taking stdout twice from the same Child.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- credential handoff could not write to stdout
- Failed to capture stdout
- stderr unavailable
- 125
- Cannot resolve current binary path
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/35633e40178342a3.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/lib.rs:10557
let spec =
CommandSpec::program(program, args.to_vec(), cwd.clone(), timeout).with_policy(policy);
let manager = SandboxManager::new();
let exec_env = manager.prepare(&spec);
let mut cmd = Command::new(exec_env.program());
cmd.args(exec_env.args())
.current_dir(&exec_env.cwd)
.stdout(Stdio::piped())
.stderr(Stdio::piped());
child_env::apply_to_command(&mut cmd, child_env::string_map_env(&exec_env.env));
let mut child = cmd
.spawn()
.map_err(|e| anyhow::anyhow!("Failed to run command: {e}"))?;
let stdout_handle = child
.stdout
.take()
.ok_or_else(|| anyhow::anyhow!("stdout unavailable"))?;
let stderr_handle = child
.stderr
.take()
.ok_or_else(|| anyhow::anyhow!("stderr unavailable"))?;
let timeout = exec_env.timeout;
let stdout_thread = std::thread::spawn(move || {
let mut reader = stdout_handle;
let mut buf = Vec::new();
let _ = reader.read_to_end(&mut buf);
buf
});
let stderr_thread = std::thread::spawn(move || {
let mut reader = stderr_handle;
let mut buf = Vec::new();
let _ = reader.read_to_end(&mut buf);
buf
});View on GitHub (pinned to 73e0f67d83)