dbt-labs/dbt-core · error
failed to write to stdout
Error message
failed to write to stdout
What it means
The TUI layer writes pending-skip output lines to stdout with write_all and unwraps with .expect("failed to write to stdout"). Rust std write_all returns Err when the underlying stdout is closed or unwritable (e.g. broken pipe), and this expect turns that into a panic.
Source
Thrown at crates/dbt-common/src/tracing/layers/tui_layer.rs:260
skipped.seen_unit_test,
true,
));
// Clear the pending names and flags
skipped.pending_names.clear();
skipped.seen_test = false;
skipped.seen_unit_test = false;
}
},
);
// Emit the output after the span lock has been released to avoid possible deadlocks
if let Some(output) = output_to_emit {
tui.write_suspended(|| {
io::stdout()
.lock()
.write_all(format!("{}\n", output).as_bytes())
.expect("failed to write to stdout");
});
}
}
fn node_evaluated_progress_status(
span_status: Option<&SpanStatus>,
ne: &NodeEvaluated,
) -> Option<&'static str> {
match ne.node_outcome() {
NodeOutcome::Success if get_test_outcome(ne.into()) == Some(TestOutcome::Failed) => {
Some("failed")
}
NodeOutcome::Success => Some("succeeded"),
NodeOutcome::Error => Some("failed"),
NodeOutcome::Canceled => Some("cancelled"),
NodeOutcome::Skipped => match ne.node_skip_reason() {
NodeSkipReason::Cached => Some("reused"),
NodeSkipReason::NoOp => Some("no-op"),View on GitHub (pinned to 0267ce9170)
Solutions
- Avoid piping dbt output to commands that exit early, or run without the TUI layer (use --log-format json/text with a stable sink)
- Check disk space and that the output file/pipe target is writable
- In code, handle io::Error instead of .expect — specifically ignore io::ErrorKind::BrokenPipe
Example fix
// before
io::stdout()
.lock()
.write_all(format!("{}\n", output).as_bytes())
.expect("failed to write to stdout");
// after
if let Err(e) = io::stdout().lock().write_all(format!("{}\n", output).as_bytes()) {
if e.kind() != io::ErrorKind::BrokenPipe {
eprintln!("failed to write to stdout: {e}");
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// before relying on stdout, verify it is writable
use std::io::IsTerminal;
if !io::stdout().is_terminal() {
eprintln!("stdout is redirected; ensure the consumer stays alive for the whole run");
} Try / catch
match io::stdout().lock().write_all(bytes) {
Ok(()) => {}
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => { /* consumer gone; stop writing */ }
Err(e) => eprintln!("stdout write failed: {e}"),
} Prevention
- Do not pipe dbt output into commands that exit early (head, less -F)
- Redirect to a file when output consumers may terminate early
- Monitor disk space when redirecting large run logs
When it happens
Trigger: emit_pending_skips fires on span end / node processed while stdout has been closed or its reader exited — e.g. `dbt ... | head`, redirection to a full disk, or a supervisor that closed the pipe.
Common situations: Piping dbt output into `head`/`less -F` that exits early, running dbt under CI systems that kill the log stream, or stdout redirected to a file on a full filesystem.
Related errors
- failed to write to stderr
- failed to write header to stdout
- failed to write show data to stdout
- failed to write show result to stdout
- failed to write compiled code to stdout
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/26cbc03fbef788fe.
Report an issue: GitHub.