facebook/flow · error

failed to read stdin

Error message

failed to read stdin

What it means

When `flow ast` is invoked without a filename it reads the whole document from stdin via stdin().read_to_string and calls .expect("failed to read stdin") on the result — so any read error panics the CLI rather than printing a graceful message. The dominant cause is invalid UTF-8: read_to_string decodes into a String and fails on non-UTF-8 bytes (binary or legacy-encoded input). A closed/broken stdin pipe produces the same panic.

Source

Thrown at rust_port/crates/flow_cli/src/ast_command.rs:145

    let spec = command_utils::add_offset_style_flag(spec);
    let spec = command_utils::add_from_flag(spec);
    let spec = command_utils::add_path_flag(spec);
    spec.anon("file", &arg_spec::optional(arg_spec::string()))
}

enum AstResultType {
    AstJson(flow_parser::ast::expression::Expression<flow_parser::loc::Loc, flow_parser::loc::Loc>),
    AstJs(flow_parser::ast::Program<flow_parser::loc::Loc, flow_parser::loc::Loc>),
}

fn get_file(path: Option<String>, filename: Option<String>) -> FileInput {
    match filename {
        Some(filename) => FileInput::FileName(command_utils::expand_path(&filename)),
        None => {
            let mut content = String::new();
            std::io::stdin()
                .read_to_string(&mut content)
                .expect("failed to read stdin");
            FileInput::FileContent(path, content.into())
        }
    }
}

fn offset(
    offset_table: &flow_parser::offset_utils::OffsetTable,
    position: flow_parser::loc::Position,
) -> usize {
    offset_table.offset(position).unwrap() as usize
}

fn translate_token(
    offset_table: &flow_parser::offset_utils::OffsetTable,
    token: &flow_parser::TokenSinkResult,
) -> serde_json::Value {
    let context = match token.token_context {
        flow_parser::LexMode::Normal => "normal",

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Pass a filename argument instead of stdin when the input may not be UTF-8 clean — the file path branch does not do the stdin decode.
  2. Convert the input first: iconv -t UTF-8 file.js | flow ast.
  3. Check what is actually being piped (file / xxd) — a binary file in the glob is usually the surprise.

Example fix

# before: non-UTF-8 bytes panic with 'failed to read stdin'
cat legacy.js | flow ast

# after: convert encoding first, or point at a file
iconv -t UTF-8 legacy.js | flow ast
flow ast --filename legacy-utf8.js
Defensive patterns

Strategy: validation

Validate before calling

# Validate the payload is UTF-8 before piping it to `flow ast`.
iconv -t UTF-8 input.js >/dev/null 2>&1 || echo "input is not UTF-8"
# or: file -bi input.js  -> charset must be utf-8/us-ascii

Prevention

When it happens

Trigger: Piping a file with non-UTF-8 bytes into `flow ast` (cat legacy.js | flow ast with no filename flag), piping a binary file picked by a glob, or running the command with stdin closed or redirected from a dead fd.

Common situations: Latin-1/Windows-1252 encoded sources; minified third-party bundles with stray bytes; CI invoking the command with no stdin attached; an upstream producer crashing mid-pipe so the read end errors.

Related errors


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