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
- 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.
- Convert the input first: iconv -t UTF-8 file.js | flow ast.
- 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
- Normalize all source files to UTF-8 in the repo (add an encoding lint).
- Prefer passing a filename argument over stdin when input provenance is unknown.
- In scripts, check encodings with `file` before piping into Flow CLI commands.
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.