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

  1. Verify the path exists and ends with .bin (use abstio::file_exists before calling).
  2. If the file may be absent or corrupt, call maybe_read_binary and handle the Err instead of read_binary.
  3. Regenerate the .bin file with the current write_binary / data schema; stale or corrupt files must be rebuilt.
  4. 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

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


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)