XAMPPRocky/tokei · error

Couldn't read file

Error message

Couldn't read file

What it means

This panic comes from an `.expect("Couldn't read file")` on `file.read_to_string()` inside `add_input` (src/input.rs:176). The file was successfully *opened* via `File::open`, but reading its bytes into a `String` failed. By far the most common cause is `InvalidData`: the file contains bytes that are not valid UTF-8, since `read_to_string` requires valid UTF-8. Other I/O errors (device errors, permission changes mid-read) can also trigger it.

Source

Thrown at src/input.rs:176

    (json, "json", Json [serde_json]) =>
        serde_json::from_str,
        serde_json::to_string,

    (yaml, "yaml", Yaml [serde_yaml]) =>
        serde_yaml::from_str,
        serde_yaml::to_string,
);

pub fn add_input(input: &str, languages: &mut Languages) -> bool {
    use std::fs::File;
    use std::io::Read;

    let map = match File::open(input) {
        Ok(mut file) => {
            let contents = {
                let mut contents = String::new();
                file.read_to_string(&mut contents)
                    .expect("Couldn't read file");
                contents
            };

            convert_input(&contents)
        }
        Err(_) => {
            if input == "stdin" {
                let mut stdin = ::std::io::stdin();
                let mut buffer = String::new();

                let _ = stdin.read_to_string(&mut buffer);
                convert_input(&buffer)
            } else {
                convert_input(input)
            }
        }
    };

View on GitHub (pinned to fa44e51940)

Solutions

  1. Re-encode or fix the input file as valid UTF-8 (e.g. `iconv -f WINDOWS-1252 -t UTF-8 in.txt > out.txt`) and retry
  2. Verify the path points to a regular UTF-8 text file, not a binary/special file, before invoking the tool
  3. Replace the `.expect` with graceful handling: match on the `io::Error` kind (`ErrorKind::InvalidData`) and fall back to reading bytes with `String::from_utf8_lossy` or skip the file with a warning
  4. If input may be binary, open with `File::open` + `read_to_end` into `Vec<u8>` and convert with `String::from_utf8_lossy` instead of `read_to_string`

Example fix

// before
file.read_to_string(&mut contents)
    .expect("Couldn't read file");
// after
if let Err(e) = file.read_to_string(&mut contents) {
    if e.kind() == std::io::ErrorKind::InvalidData {
        eprintln!("{} is not valid UTF-8; skipping", input);
        return false;
    }
    panic!("Couldn't read file: {}", e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

fn is_valid_utf8_file(path: &str) -> bool {
    use std::fs::File;
    use std::io::Read;
    let mut f = match File::open(path) { Ok(f) => f, Err(_) => return false };
    let mut buf = Vec::new();
    if f.read_to_end(&mut buf).is_err() { return false; }
    String::from_utf8(buf).is_ok()
}
// call before: if !is_valid_utf8_file(input) { /* skip or convert */ }

Type guard

fn is_text_file(path: &str) -> bool {
    std::fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
        && is_valid_utf8_file(path)
}

Try / catch

match file.read_to_string(&mut contents) {
    Ok(_) => { /* proceed with contents */ }
    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
        eprintln!("Input is not valid UTF-8: {}", e);
        // fall back: read bytes and String::from_utf8_lossy
    }
    Err(e) => { eprintln!("Couldn't read file: {}", e); return false; }
}

Prevention

When it happens

Trigger: Calling `add_input(path)` (e.g. via the CLI's input argument) on a file that opens successfully but whose contents are not valid UTF-8 — e.g. a binary file, a Latin-1/UTF-16 encoded file, or a file with a BOM-less non-UTF-8 encoding. `File::open` succeeds (existence/permissions are fine) so the `Err(_)` fallback that treats the input as inline text is skipped, and the subsequent `read_to_string` panics.

Common situations: Passing a binary blob or compiled artifact as an input file; counting a project whose source files are saved in a legacy encoding (Windows-1252, Shift-JIS, UTF-16); a broken symlink resolving to a special file; reading from /proc or a device file where open succeeds but read fails.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of XAMPPRocky/tokei@fa44e51940 (2026-09-06). Data as JSON: /api/errors/a495fe038e06a801. Report an issue: GitHub.