{"record":{"id":"f532a3053757e712","repo":"dbt-labs/dbt-core","slug":"failed-to-write-header-to-stdout","errorCode":null,"errorMessage":"failed to write header to stdout","messagePattern":"failed to write header to stdout","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbt-common/src/tracing/layers/tui_layer.rs","lineNumber":1411,"sourceCode":"    }\n\n    fn handle_list_item_output(&self, list_item: &ListItemOutput) {\n        if self.show_options.contains(&ShowOptions::Nodes) || self.command == FsCommand::List {\n            self.write_suspended(|| {\n                let mut stdout = io::stdout().lock();\n\n                // Only emit the decorative header when show_options is non-empty (i.e. not quiet).\n                // In quiet mode show_options is cleared, so the header is suppressed while list\n                // item content (the result payload) continues to be printed — matching dbt-core's\n                // PrintEvent behaviour where only decorative chrome is stripped.\n                if !self.show_options.is_empty()\n                    && !self.list_header_emitted.swap(true, Ordering::Relaxed)\n                {\n                    let header =\n                        format_delimiter(SELECTED_NODES_TITLE, self.max_term_line_width, true);\n                    stdout\n                        .write_all(format!(\"{}\\n\", header).as_bytes())\n                        .expect(\"failed to write header to stdout\");\n                }\n\n                // Print list item content (always — result payload survives quiet)\n                stdout\n                    .write_all(format!(\"{}\\n\", list_item.content).as_bytes())\n                    .expect(\"failed to write to stdout\");\n            });\n        }\n    }\n\n    fn handle_show_data_output(&self, show_data: &ShowDataOutput) {\n        self.write_suspended(|| {\n            let mut stdout = io::stdout().lock();\n\n            stdout\n                .write_all(format!(\"{}\\n\", show_data.content).as_bytes())\n                .expect(\"failed to write show data to stdout\");\n        });","sourceCodeStart":1393,"sourceCodeEnd":1429,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-common/src/tracing/layers/tui_layer.rs#L1393-L1429","documentation":"handle_list_item_output writes the 'SELECTED NODES' delimiter header (once, guarded by an AtomicBool) using .expect('failed to write header to stdout'), panicking on write failure. The header write happens inside write_suspended while rendering `dbt list` output. A broken stdout makes listing output delivery fatal.","triggerScenarios":"First list-item log record after quiet filtering (on_log_record) triggers the header write while the pipe consumer has exited or stdout is invalid.","commonSituations":"`dbt list | head -n 5` — head exits after 5 lines and the next write fails; listing into a closed socket; redirected output on a full disk.","solutions":["Consume the full pipe output or redirect to a file: `dbt list > nodes.txt`","Use `dbt list | sed -n '1,5p'` alternatives carefully — prefer file redirection for truncation","Verify the capturing process stays alive in CI","Harden the layer to treat stdout errors as end-of-output rather than panic"],"exampleFix":"// before\n.expect(\"failed to write header to stdout\");\n// after\nif stdout.write_all(format!(\"{}\\n\", header).as_bytes()).is_err() {\n    return; // stdout gone; stop emitting\n}","handlingStrategy":"try-catch","validationCode":"# capture the full listing to a file before truncating\ndbt list > nodes.txt 2>&1 && head -n 5 nodes.txt","typeGuard":"fn stdout_writable() -> bool {\n    use std::io::Write;\n    io::stdout().flush().is_ok()\n}","tryCatchPattern":"// catch pipe failure and fall back to file-based listing\ndbt list 2>err.log || { grep -q 'failed to write header to stdout' err.log && dbt list > out.txt; }","preventionTips":["Never do `dbt list | head`; list to a file and head the file","Count expected nodes first so truncation surprises are avoided","Use tee if live filtering is required","Ensure CI wrappers read all of dbt's output"],"tags":["stdout","io","broken-pipe","dbt-list"],"backgroundTag":"broken-pipe","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}