a-b-street/abstreet · error

Can't maybe_read_binary

Error message

Can't maybe_read_binary {}, it doesn't exist

What it means

On web, abstio::maybe_read_binary deserializes bincode data either from the embedded SYSTEM_DATA archive (paths under ../data/system/) or from localStorage (paths under data/player/). If the path matches neither source, it bails with "Can't maybe_read_binary ..., it doesn't exist".

Solutions

  1. Verify the path starts with ../data/system/ or the player data prefix and that the file was included in the web build.
  2. Provide a fallback/default value with maybe_read_binary when the item may legitimately not exist yet.
  3. Rebuild the web bundle so new binary data is embedded.

Example fix

// before
let map = abstio::maybe_read_binary::<Map>(map_path, timer).ok();
// after
let map = abstio::maybe_read_binary::<Map>(map_path, timer)
    .map_err(|_| anyhow!("map {} not embedded in web build", map_path))?;
Defensive patterns

Strategy: fallback

Validate before calling

let readable = path.starts_with("../data/system/") || path.starts_with(&abstio::path_player(""));

Try / catch

let value = abstio::maybe_read_binary::<T>(path, timer).unwrap_or_else(|_| T::default());

Prevention

When it happens

Trigger: Requesting a .bin system file not present in the web bundle; using a path that is neither system- nor player-prefixed; reading a player file that was never saved to localStorage.

Common situations: Fresh browser session where nothing was ever saved to localStorage; new binary data files not yet baked into the web build; mistyped or non-normalized paths.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/2456ace61c2ad54a. Report an issue: GitHub.

Appendix: source

Thrown at abstio/src/io_web.rs:114

            use base64::Engine;
            let bytes = base64::engine::general_purpose::STANDARD.decode(string)?;
            Ok(bytes)
        }
    } else {
        bail!("Can't slurp_file {}, it doesn't exist", path)
    }
}

pub fn maybe_read_binary<T: DeserializeOwned>(path: String, _: &mut Timer) -> Result<T> {
    if let Some(raw) = SYSTEM_DATA.get_file(path.trim_start_matches("../data/system/")) {
        bincode::deserialize(raw.contents()).map_err(|err| err.into())
    } else if path.starts_with(&path_player("")) {
        let string = read_local_storage(&path)?;
        use base64::Engine;
        let out = bincode::deserialize(&base64::engine::general_purpose::STANDARD.decode(string)?)?;
        Ok(out)
    } else {
        bail!("Can't maybe_read_binary {}, it doesn't exist", path)
    }
}

pub fn write_json<T: Serialize>(path: String, obj: &T) {
    // Only save for data/player, for now
    if !path.starts_with(&path_player("")) {
        warn!("Not saving {}", path);
        return;
    }

    let window = web_sys::window().unwrap();
    let storage = window.local_storage().unwrap().unwrap();
    storage.set_item(&path, &abstutil::to_json(obj)).unwrap();
}

pub fn write_binary<T: Serialize>(path: String, obj: &T) {
    write_raw(path, &abstutil::to_binary(obj)).unwrap();
}

View on GitHub (pinned to 0964f29315)