a-b-street/abstreet · error
Couldn't read_binary
Error message
Couldn't read_binary({}): {} What it means
read_binary loads a bincode-serialized file (path must end with .bin) and deserializes it into T. On any failure it panics with this message instead of returning a Result. Failures come from maybe_read_binary: a missing/unreadable file, a Timer I/O error, or bincode deserialization failure (corrupt or wrong-type data). Use maybe_read_binary if you need recoverable errors.
Solutions
- Verify the path exists and ends with .bin (use abstio::file_exists before calling).
- If the file may be absent or corrupt, call maybe_read_binary and handle the Err instead of read_binary.
- Regenerate the .bin file with the current write_binary / data schema; stale or corrupt files must be rebuilt.
- Check that the bincode version/config matches whatever wrote the file, and that T matches the serialized type.
Example fix
// before
let map = abstio::read_binary::<Map>("data/map.bin".to_string(), &mut timer);
// after
let map = match abstio::maybe_read_binary::<Map>("data/map.bin".to_string(), &mut timer) {
Ok(m) => m,
Err(err) => {
eprintln!("falling back: {}", err);
build_default_map(&mut timer)
}
}; Defensive patterns
Strategy: fallback
Validate before calling
if !abstio::file_exists(&path) || !path.ends_with(".bin") {
eprintln!("{} missing or not a .bin file; using fallback", path);
} Type guard
fn is_bin_path(path: &str) -> bool {
path.ends_with(".bin") && std::path::Path::new(path).is_file()
} Try / catch
// Rust panics can be caught, but prefer the Result API:
match abstio::maybe_read_binary::<T>(path.clone(), &mut timer) {
Ok(obj) => obj,
Err(err) => { eprintln!("read_binary failed: {}", err); fallback() }
} Prevention
- Prefer maybe_read_binary (Result) over read_binary whenever the file may be absent or corrupt.
- Always check the extension is .bin before calling.
- Regenerate .bin artifacts whenever the data schema or bincode version changes.
- Use write_binary so files are written atomically-enough; avoid killing processes mid-write.
When it happens
Trigger: Calling read_binary(path, timer) where the path does not exist or is unreadable; the path does not end with '.bin' (maybe_read_binary panics on that separately); the file's bytes are not valid bincode or do not match T (schema/format mismatch); the file was truncated or produced by a different bincode configuration.
Common situations: Pointing at a JSON file with a .bin name or vice versa; stale .bin files left over after data-format changes between versions; partially written or corrupted .bin files from an interrupted run; passing a path relative to the wrong working directory.
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
- Couldn't read_json( )
- Couldn't read_object
- Can't write_json( )
- Can't write_binary( )
- Compressed not there?
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/290b4283aa9c232a.
Report an issue: GitHub.
Appendix: source
Thrown at abstio/src/io.rs:33
timer.start(format!("parse {}", path));
// TODO timer.read_file isn't working here. And we need to call stop() if there's no file.
let result: Result<T> =
slurp_file(&path).and_then(|raw| serde_json::from_slice(&raw).map_err(|err| err.into()));
timer.stop(format!("parse {}", path));
result
}
pub fn read_json<T: DeserializeOwned>(path: String, timer: &mut Timer) -> T {
match maybe_read_json(path.clone(), timer) {
Ok(obj) => obj,
Err(err) => panic!("Couldn't read_json({}): {}", path, err),
}
}
pub fn read_binary<T: DeserializeOwned>(path: String, timer: &mut Timer) -> T {
match maybe_read_binary(path.clone(), timer) {
Ok(obj) => obj,
Err(err) => panic!("Couldn't read_binary({}): {}", path, err),
}
}
/// May be a JSON or binary file
pub fn read_object<T: DeserializeOwned>(path: String, timer: &mut Timer) -> Result<T> {
if path.ends_with(".bin") {
maybe_read_binary(path, timer)
} else {
maybe_read_json(path, timer)
}
}
/// May be a JSON or binary file. Panics on failure.
pub fn must_read_object<T: DeserializeOwned>(path: String, timer: &mut Timer) -> T {
match read_object(path.clone(), timer) {
Ok(obj) => obj,
Err(err) => panic!("Couldn't read_object({}): {}", path, err),
}View on GitHub (pinned to 0964f29315)