{"record":{"id":"00f22ef9e4a25cee","repo":"facebook/flow","slug":"failed-to-flush-cli-errors-00f22e","errorCode":null,"errorMessage":"failed to flush cli errors","messagePattern":"failed to flush cli errors","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_cli/src/status_command.rs","lineNumber":201,"sourceCode":"                out.flush().expect(\"failed to flush vim/emacs errors\");\n            } else {\n                let mut cli_errors = errors.clone();\n                for (error, _) in &suppressed_errors {\n                    cli_errors.add(error.clone());\n                }\n                let stdout = std::io::stdout();\n                let mut out = stdout.lock();\n                flow_common_errors::error_utils::cli_output::print_errors(\n                    &mut out,\n                    error_flags,\n                    &None,\n                    strip_root.as_deref(),\n                    &cli_errors,\n                    &warnings,\n                    lazy_msg.as_deref(),\n                )\n                .expect(\"failed to write cli errors\");\n                out.flush().expect(\"failed to flush cli errors\");\n            }\n            flow_common_exit_status::exit(command_utils::get_check_or_status_exit_code(\n                &errors,\n                &warnings,\n                error_flags.max_warnings,\n            ))\n        }\n        server_prot::response::StatusResponse::NO_ERRORS => {\n            if args.output_json {\n                print_json(\n                    &ConcreteLocPrintableErrorSet::empty(),\n                    &ConcreteLocPrintableErrorSet::empty(),\n                    &[],\n                )\n            } else {\n                println!(\"No errors!\");\n                if let Some(msg) = &lazy_msg {\n                    println!(\"\\n{}\", msg);","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_cli/src/status_command.rs#L183-L219","documentation":"After printing the collected error/warning report to a locked stdout handle, the flow status-style command flushes the buffer with `out.flush().expect(\"failed to flush cli errors\")`. The panic fires when the flush itself returns an IO error, which in practice means the process on the other end of stdout has gone away (EPIPE/BrokenPipe) or stdout was closed. Rust ignores SIGPIPE by default, so instead of dying silently the write error surfaces here as a panic.","triggerScenarios":"Running the command with stdout piped to a short-lived reader that exits before all error output is written: `flow status | head`, `flow check | grep -m1 pattern`, a pager the user quits early, or a log collector that closes the pipe. Also triggered by deliberately closing fd 1 (`>&-`).","commonSituations":"Shell scripts and CI pipelines that pipe flow CLI output into head/less/grep; wrapper processes that close stdout before the command finishes; large error dumps that outlive a `head -n 10` reader.","solutions":["Avoid killing the reader early: write to a file or terminal (`flow status > report.txt`) instead of piping into head/grep -m.","If scripting, consume the full output or redirect to a file so the pipe never breaks mid-flush.","If you own the code, treat BrokenPipe as a clean exit: match on `out.flush()` and exit 0 on ErrorKind::BrokenPipe instead of expect.","In wrapper processes, restore default SIGPIPE behavior (`libc::signal(SIGPIPE, SIG_DFL)`) so the process exits quietly rather than panicking."],"exampleFix":"// before\nout.flush().expect(\"failed to flush cli errors\");\n\n// after\nif let Err(e) = out.flush() {\n    if e.kind() != std::io::ErrorKind::BrokenPipe {\n        panic!(\"failed to flush cli errors: {e}\");\n    }\n    std::process::exit(0); // reader went away; report was effectively delivered\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let flush_result = out.flush();\nif let Err(e) = flush_result {\n    if e.kind() == std::io::ErrorKind::BrokenPipe {\n        std::process::exit(0); // reader went away; treat as success\n    }\n    panic!(\"failed to flush cli errors: {e}\");\n}","preventionTips":["Do not pipe flow CLI output into readers that exit early (head, grep -m, quitting pagers); write to files in scripts.","In wrapper processes, restore default SIGPIPE (`libc::signal(libc::SIGPIPE, libc::SIG_DFL)`) so pipe closure ends the process quietly instead of panicking.","Keep stdout/stderr readers alive for the full duration of the command."],"tags":["stdout","broken-pipe","io-flush","cli"],"backgroundTag":"broken-pipe","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}