Hmbown/CodeWhale · error · anyhow::Error
Failed to capture stderr
Error message
Failed to capture stderr
What it means
Mirror of the stdout case: in the separated-stream path the child must have a piped stderr handle (child.stderr.take()); if None, the child is terminated and 'Failed to capture stderr' returns. Note that some modes (tty, persist_pending, small_contract) intentionally leave the stderr buffer unset, but the handle itself must still exist when this branch runs — None here means the spawn did not pipe stderr at all, an internal invariant break.
Source
Thrown at crates/tui/src/tools/shell.rs:2545
if let (Some(reader), Some(output)) = (combined_reader, bounded_output.as_ref()) {
(
Some(spawn_bounded_reader_thread(reader, Arc::clone(output))),
None,
)
} else {
let stdout_handle = child.stdout.take().ok_or_else(|| {
#[cfg(windows)]
terminate_unregistered_process(&mut child, windows_job.as_ref());
#[cfg(not(windows))]
terminate_unregistered_process(&mut child);
anyhow!("Failed to capture stdout")
})?;
let stderr_handle = child.stderr.take().ok_or_else(|| {
#[cfg(windows)]
terminate_unregistered_process(&mut child, windows_job.as_ref());
#[cfg(not(windows))]
terminate_unregistered_process(&mut child);
anyhow!("Failed to capture stderr")
})?;
(
Some(spawn_reader_thread(
stdout_handle,
Arc::clone(&stdout_buffer),
)),
stderr_buffer
.as_ref()
.map(|buffer| spawn_reader_thread(stderr_handle, Arc::clone(buffer))),
)
};
(
ShellChild::Process(child),
stdin_handle,
stdout_thread,
stderr_thread,
)View on GitHub (pinned to 0c42157ee5)
Solutions
- Retry the command once to rule out a transient spawn issue.
- If reproducible, report upstream with command, flags (background, tty, persist), and platform.
- Workaround: background execution with bounded/combined output avoids the separated stderr thread.
Defensive patterns
Strategy: retry
Try / catch
let out = match exec_shell(cmd, dir, opts).await {
Ok(o) => o,
Err(e) if e.to_string().contains("Failed to capture stderr") => {
exec_shell(cmd, dir, opts).await
.or_else(|_| exec_shell_background_bounded(cmd, dir))?
}
Err(e) => return Err(e),
}; Prevention
- Use background/bounded output capture when you depend on stderr content.
- Capture the exact command and spawn options if seen — it indicates a spawn/capture mismatch, not a caller error.
When it happens
Trigger: Child spawned without Stdio::piped() stderr while the separated-reader path assumes it; internal regression or platform spawn quirk, not a caller-selectable condition.
Common situations: Rare; not triggerable through documented tool options. Would appear after modifying spawn stdio configuration.
Related errors
- Failed to capture stdout
- stdin is not available for task {}
- Persistent service has no process group id
- tmux new-session failed with {status}
- MCP server '{server_name}' has no command configured
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/fbaa2a23777cec0d.
Report an issue: GitHub.