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
- 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
- Verify the path points to a regular UTF-8 text file, not a binary/special file, before invoking the tool
- 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
- 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
- Verify inputs are UTF-8 text before passing them (run `file` or `iconv -f UTF-8 -t UTF-8` as a sanity check)
- Avoid pointing the tool at binary artifacts, images, or special/device files
- Normalize legacy encodings to UTF-8 in a preprocessing step
- In library code, prefer returning `io::Result` over `.expect`/`.unwrap` on reads so callers can handle encoding failures
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.