{"record":{"id":"98a0fec358b2d0a6","repo":"facebook/flow","slug":"failed-to-write-success-output","errorCode":null,"errorMessage":"failed to write success output","messagePattern":"failed to write success output","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_cli/src/check_contents_command.rs","lineNumber":188,"sourceCode":"                // Return a successful exit code if there were only warnings.\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        }\n        server_prot::response::StatusResponse::NO_ERRORS => {\n            if json {\n                print_json(\n                    &ConcreteLocPrintableErrorSet::empty(),\n                    &ConcreteLocPrintableErrorSet::empty(),\n                    &[],\n                )\n            } else {\n                let stdout = std::io::stdout();\n                let mut out = stdout.lock();\n                writeln!(out, \"No errors!\").expect(\"failed to write success output\");\n                out.flush().expect(\"failed to flush success output\");\n            }\n            flow_common_exit_status::exit(flow_common_exit_status::FlowExitStatus::NoError)\n        }\n        server_prot::response::StatusResponse::NOT_COVERED => {\n            if json {\n                print_json(\n                    &ConcreteLocPrintableErrorSet::empty(),\n                    &ConcreteLocPrintableErrorSet::empty(),\n                    &[],\n                )\n            } else {\n                let stdout = std::io::stdout();\n                let mut out = stdout.lock();\n                writeln!(out, \"File is not @flow!\").expect(\"failed to write not-covered output\");\n                out.flush().expect(\"failed to flush not-covered output\");\n            }\n            flow_common_exit_status::exit(flow_common_exit_status::FlowExitStatus::NoError)","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_cli/src/check_contents_command.rs#L170-L206","documentation":"Happy path of check-contents: the server answers StatusResponse::NO_ERRORS and, without --json, the CLI writes the single line 'No errors!' to locked stdout. Even one writeln can fail: once the pipe's read end is fully closed (consumer exited or fd closed), any write returns EPIPE immediately, so the .expect() panics before the NoError exit status is set.","triggerScenarios":"`flow check-contents file.js | true` or a fast-failing validation step that exits without reading; a consumer that exits before the CLI's write lands (race); stdout closed via `>&-` or an invalid redirect.","commonSituations":"Scripts using `cmd | grep -q SomethingElse` patterns where the probe exits; wrappers that spawn the CLI but close the pipe early on their own error paths; sandboxed environments closing stdout fds.","solutions":["Capture to a file and test the file: `flow check-contents file.js > out.txt; test $? -eq 0`","Make the downstream consumer read until EOF instead of exiting early","Ensure the CLI's stdout is a live pipe or file (never closed) in wrappers","Maintainer: match the writeln result and exit(141) on BrokenPipe instead of expect"],"exampleFix":"// before\nwriteln!(out, \"No errors!\").expect(\"failed to write success output\");\n\n// after\nif let Err(e) = writeln!(out, \"No errors!\") {\n    if e.kind() == std::io::ErrorKind::BrokenPipe {\n        std::process::exit(141);\n    }\n    panic!(\"failed to write success output: {e}\");\n}","handlingStrategy":"try-catch","validationCode":"// Consumers should read until EOF rather than exit early:\n// (pattern for a wrapper that inspects output then decides)\n// flow check-contents file.js > out.txt   # always drains the writer","typeGuard":null,"tryCatchPattern":"if let Err(e) = writeln!(out, \"No errors!\") {\n    if e.kind() == std::io::ErrorKind::BrokenPipe {\n        std::process::exit(141);\n    }\n    panic!(\"failed to write success output: {e}\");\n}","preventionTips":["Branch on exit codes instead of matching on streamed output text","Do not wrap the CLI in pipelines whose stages may exit before reading","Keep stdout attached to a file or a durable reader in automation"],"tags":["rust","flow-cli","stdout","broken-pipe","panic"],"backgroundTag":"broken-pipe","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-08-23T11:17:13.642Z"}