facebook/flow · error

failed to flush success output

Error message

failed to flush success output

What it means

Flush right after the 'No errors!' line in check-contents. Because a single short line fits in the kernel pipe buffer, the writeln usually succeeds even if the reader is finishing; the reader then fully exits (e.g. grep -q matched the line), the pipe's read end closes, and this explicit out.flush() gets EPIPE — the canonical race that the .expect() turns into a panic.

Source

Thrown at rust_port/crates/flow_cli/src/check_contents_command.rs:189

                flow_common_exit_status::exit(command_utils::get_check_or_status_exit_code(
                    &errors,
                    &warnings,
                    error_flags.max_warnings,
                ))
            }
        }
        server_prot::response::StatusResponse::NO_ERRORS => {
            if json {
                print_json(
                    &ConcreteLocPrintableErrorSet::empty(),
                    &ConcreteLocPrintableErrorSet::empty(),
                    &[],
                )
            } else {
                let stdout = std::io::stdout();
                let mut out = stdout.lock();
                writeln!(out, "No errors!").expect("failed to write success output");
                out.flush().expect("failed to flush success output");
            }
            flow_common_exit_status::exit(flow_common_exit_status::FlowExitStatus::NoError)
        }
        server_prot::response::StatusResponse::NOT_COVERED => {
            if json {
                print_json(
                    &ConcreteLocPrintableErrorSet::empty(),
                    &ConcreteLocPrintableErrorSet::empty(),
                    &[],
                )
            } else {
                let stdout = std::io::stdout();
                let mut out = stdout.lock();
                writeln!(out, "File is not @flow!").expect("failed to write not-covered output");
                out.flush().expect("failed to flush not-covered output");
            }
            flow_common_exit_status::exit(flow_common_exit_status::FlowExitStatus::NoError)
        }

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Use the exit code instead of probing output: `flow check-contents file.js && echo ok`
  2. Capture to a file and grep the file rather than the stream
  3. Wrap the pipeline in a buffer (`| cat`) so the flush always finds a live reader
  4. Maintainer: exit quietly (141) on BrokenPipe at the flush instead of expect

Example fix

// before
out.flush().expect("failed to flush success output");

// after
if let Err(e) = out.flush() {
    if e.kind() == std::io::ErrorKind::BrokenPipe {
        std::process::exit(141);
    }
    panic!("failed to flush success output: {e}");
}
Defensive patterns

Strategy: try-catch

Try / catch

if let Err(e) = out.flush() {
    if e.kind() == std::io::ErrorKind::BrokenPipe {
        std::process::exit(141);
    }
    panic!("failed to flush success output: {e}");
}

Prevention

When it happens

Trigger: `flow check-contents file.js | grep -q 'No errors'` — grep matches the line, exits, and the subsequent flush hits EPIPE; a probe command exiting between the write and the flush; flush to a full filesystem.

Common situations: CI pipelines that assert on success output via grep -q; short-output commands piped into probes; redirects to full volumes.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/e8a39cc16d0575de. Report an issue: GitHub.