facebook/flow · error

failed to write errors

Error message

failed to write errors

What it means

After a foreground (check-and-die) run with JSON output (e.g. `flow check-contents --json --pretty`), the CLI formats the error report and writes it to a BufWriter over stdout. This expect is on the pretty-printed branch (flow_hh_json::json_to_multiline) and panics on any write error. Because Rust ignores SIGPIPE, a downstream consumer that exited early surfaces here as ErrorKind::BrokenPipe instead of a signal.

Source

Thrown at rust_port/crates/flow_cli/src/foreground_check_commands.rs:84

            let strip_root = strip_root.map(|path| path.to_string_lossy().into_owned());
            let pretty = *pretty;
            let get_json = json_output::full_status_json_of_errors(
                strip_root.as_deref(),
                suppressed_errors,
                version.clone().unwrap_or(json_output::JsonVersion::JsonV1),
                &None,
                offset_kind,
                errors,
                warnings,
            );
            let finish_formatting = move |profiling_props| {
                let res = get_json(profiling_props);
                let stdout = std::io::stdout();
                let mut out = std::io::BufWriter::new(stdout.lock());
                use std::io::Write;
                if pretty {
                    write!(out, "{}", flow_hh_json::json_to_multiline(&res))
                        .expect("failed to write errors");
                } else {
                    write!(out, "{}", flow_hh_json::json_string_of_value(&res))
                        .expect("failed to write errors");
                }
                out.flush().expect("failed to flush errors");
            };
            Box::new(move |profiling| {
                let profiling_props = match profiling {
                    Some(serde_json::Value::Object(profiling_props)) => {
                        profiling_props.into_iter().collect()
                    }
                    Some(_) | None => vec![],
                };
                finish_formatting(profiling_props);
            })
        }
        Printer::Cli(flags) => {
            let errors = suppressed_errors

View on GitHub (pinned to 5c86586199)

Solutions

  1. Write to a file first and inspect it separately: `flow check-contents --json --pretty > report.json`.
  2. Keep the pipe consumer alive until EOF (drop `head`/`grep -m` from the pipeline).
  3. If redirecting to a file, free disk space / raise quota.
  4. Maintainer fix: treat ErrorKind::BrokenPipe as a clean exit(0), the standard CLI convention.

Example fix

// before
write!(out, "{}", flow_hh_json::json_to_multiline(&res))
    .expect("failed to write errors");

// after
if let Err(e) = write!(out, "{}", flow_hh_json::json_to_multiline(&res)) {
    if e.kind() == std::io::ErrorKind::BrokenPipe {
        std::process::exit(0);
    }
    panic!("failed to write errors: {}", e);
}
Defensive patterns

Strategy: try-catch

Try / catch

if let Err(e) = write!(out, "{}", flow_hh_json::json_to_multiline(&res)) {
    if e.kind() == std::io::ErrorKind::BrokenPipe {
        std::process::exit(0);
    }
    panic!("failed to write errors: {}", e);
}

Prevention

When it happens

Trigger: `flow check-contents --json --pretty | head -n 5` (head exits after 5 lines, closing the pipe); a downstream filter that exits early (grep -m1, jq ... | head); stdout redirected to a full filesystem (ENOSPC); stdout closed with `>&-`.

Common situations: Piping large JSON check output into head/grep in scripts; CI capturing output to a full disk or size-capped artifact; a consumer tool crashing mid-stream.

Related errors


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