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::JsxReact

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Pass the file as the positional `file` argument (`flow env-builder-debug path/to/file.js`) so stdin is never read.
  2. Re-encode the input before piping: `iconv -f LATIN1 -t UTF-8 file.js | flow env-builder-debug`.
  3. Pre-validate encoding: `iconv -f UTF-8 -t UTF-8 file.js > /dev/null` — it fails loudly on the first invalid byte.
  4. 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

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.