Hmbown/CodeWhale · error
Stdio transport closed
Error message
Stdio transport closed
What it means
Stdout EOF with no stderr captured: the server process ended without writing anything to stderr (the ring-buffered tail was empty). Silent exits come from clean status-0 exits (e.g. --help left in args), SIGKILL/OOM kills that never get to print, or wrappers that daemonize and close stdout.
Source
Thrown at crates/tui/src/mcp/stdio.rs:327
// Bounded read: a server emitting a newline-free multi-GB "line"
// must not OOM us (read_line is unbounded).
let bytes =
match read_line_capped(&mut self.reader, &mut line_bytes, MAX_MCP_RESPONSE_BYTES)
.await
{
Ok(b) => b,
Err(err) => {
if let Some(stderr) = format_stderr_context(&self.stderr_tail).await {
anyhow::bail!("Stdio transport read error: {err}\n{stderr}");
}
return Err(err.into());
}
};
if bytes == 0 {
if let Some(stderr) = format_stderr_context(&self.stderr_tail).await {
anyhow::bail!("Stdio transport closed\n{stderr}");
}
anyhow::bail!("Stdio transport closed");
}
let line = String::from_utf8_lossy(&line_bytes);
let trimmed = line.trim();
if trimmed.is_empty() {
continue;
}
return Ok(trimmed.as_bytes().to_vec());
}
}
/// Send SIGTERM and wait up to `STDIO_SHUTDOWN_GRACE` for graceful exit,
/// then force termination and reap the child as the backstop.
async fn shutdown(&mut self) {
let mut child = self.child.lock().await;
terminate_child(&mut child).await;
}View on GitHub (pinned to 8880682c63)
Solutions
- Run the command manually and observe its exit code and output
- Check system logs (dmesg, journalctl) for OOM or signal kills of the child
- Remove flags like --help/--version from the server args
- Confirm the server is a foreground stdio MCP server, not a daemonizing wrapper
Defensive patterns
Strategy: try-catch
Type guard
```rust
fn is_silent_exit(msg: &str) -> bool {
msg.trim() == "Stdio transport closed"
}
``` Try / catch
```rust
match stdio_transport.recv().await {
Err(e) if is_silent_exit(&format!("{e:#}")) => {
check_oom_and_signal_logs(); // silent exits: OOM kill, SIGKILL, or clean exit(0)
Err(e)
}
other => other?,
}
``` Prevention
- Remove --help/--version style flags from server args
- Check dmesg/journalctl for OOM kills when the exit is silent
- Use foreground stdio servers, not daemonizing wrappers
When it happens
Trigger: The child exits immediately with code 0 (argument parsing that prints to stdout only), is killed by SIGKILL/OOM before writing stderr, or forks to the background and closes its stdio.
Common situations: A --help/--version flag accidentally left in server args; OOM killer silently terminating the child; wrapper scripts that daemonize instead of staying in the foreground.
Related errors
- Stdio transport read error: {err} {stderr}
- Stdio transport closed {stderr}
- failed to read git range {commit_range!r}: {exc}
- measurement command failed
- measurement emitted invalid JSON: {error}
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/3dbe67f9304f390f.
Report an issue: GitHub.