facebook/flow · error
failed to read stdin
Error message
failed to read stdin
What it means
`flow env-builder-debug` reads the program to parse from stdin when no positional FILE argument is supplied (get_file). std::io::stdin().read_to_string streams all of stdin and requires it to be valid UTF-8; any io error — most commonly ErrorKind::InvalidData from non-UTF-8 bytes, but also a closed stdin fd (EBADF) or a failing writer upstream — panics via this expect.
Source
Thrown at rust_port/crates/flow_cli/src/env_builder_debug_command.rs:59
"Print the env-builder result as a dependency graph for debugging purposes",
command_spec::Visibility::Internal,
format!(
"Usage: {exe_name} env-builder-debug [OPTION]... [FILE]\n\ne.g. {exe_name} env-builder-debug foo.js\nor {exe_name} env-builder-debug < foo.js\n"
),
);
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()))
}
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())
}
}
}
struct TestCx;
impl Context for TestCx {
fn enable_enums(&self) -> bool {
true
}
fn file(&self) -> FileKey {
FileKey::new(FileKeyInner::SourceFile("test.js".to_string()))
}
fn jsx(&self) -> JsxMode {
JsxMode::JsxReactView on GitHub (pinned to f88ac94bcf)
Solutions
- Pass the file as the positional `file` argument (`flow env-builder-debug path/to/file.js`) so stdin is never read.
- Re-encode the input before piping: `iconv -f LATIN1 -t UTF-8 file.js | flow env-builder-debug`.
- Pre-validate encoding: `iconv -f UTF-8 -t UTF-8 file.js > /dev/null` — it fails loudly on the first invalid byte.
- Ensure stdin is a readable fd (do not launch with `0<&-` or from a process with closed stdin).
Example fix
// before
let mut content = String::new();
std::io::stdin()
.read_to_string(&mut content)
.expect("failed to read stdin");
// after
let mut bytes = Vec::new();
std::io::stdin().read_to_end(&mut bytes).expect("failed to read stdin");
let content = match String::from_utf8(bytes) {
Ok(content) => content,
Err(e) => {
eprintln!("stdin is not valid UTF-8 at byte {}", e.utf8_error().valid_up_to());
std::process::exit(1);
}
}; Defensive patterns
Strategy: validation
Validate before calling
let mut bytes = Vec::new();
std::io::stdin().read_to_end(&mut bytes).expect("failed to read stdin");
if !std::str::from_utf8(&bytes).is_ok() {
eprintln!("stdin is not valid UTF-8; re-encode input (iconv) or pass a FILE argument");
std::process::exit(1);
} Type guard
fn is_utf8(bytes: &[u8]) -> bool {
std::str::from_utf8(bytes).is_ok()
} Try / catch
match String::from_utf8(bytes) {
Ok(content) => content,
Err(e) => {
eprintln!("stdin is not valid UTF-8 at byte {}", e.utf8_error().valid_up_to());
std::process::exit(1);
}
} Prevention
- Prefer passing the positional FILE argument over piping via stdin.
- Re-encode legacy files with iconv (-f LATIN1/-f UTF-16 -t UTF-8) before piping.
- Pre-validate with `iconv -f UTF-8 -t UTF-8 file > /dev/null`.
- Never invoke the command with stdin closed (0<&-).
When it happens
Trigger: Piping a file that is not UTF-8 into the command (`cat legacy.js | flow env-builder-debug` where legacy.js is Latin-1/UTF-16 or contains binary bytes); invoking with stdin closed (`<&-`); an upstream process in the pipeline crashing mid-write so read_to_string returns an error.
Common situations: Source files saved by legacy Windows editors (Latin-1, UTF-16 with BOM) piped into the parser; CI scripts that exec flow without wiring stdin; accidentally feeding a binary or gzip artifact into the command.
Related errors
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/674035de6d59bd3f.
Report an issue: GitHub.