a-b-street/abstreet · error

Can't slurp_file , it doesn't exist

Error message

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

What it means

On the web (wasm) target, abstio::slurp_file reads files from the bundled SYSTEM_DATA archive or localStorage. If the requested path is not present in the embedded archive, it bails with "Can't slurp_file ..., it doesn't exist". Native filesystem reads do not apply here.

Solutions

  1. Check the path spelling and that the file exists in the data/system directory included in the web build.
  2. Rebuild/refresh the web bundle so the missing file is embedded in SYSTEM_DATA.
  3. For player-generated files (data/player/*), use the local-storage-backed read path appropriate for web.

Example fix

// before
let raw = abstio::slurp_file("../data/system/missing.json", timer)?;
// after
if abstio::file_exists("../data/system/missing.json") {
    let raw = abstio::slurp_file("../data/system/missing.json", timer)?;
} else {
    bail!("expected input is missing from the web bundle");
}
Defensive patterns

Strategy: fallback

Validate before calling

if !abstio::file_exists(path) {
    bail!("{} missing from web bundle", path);
}

Try / catch

match abstio::slurp_file(path, timer) {
    Ok(raw) => raw,
    Err(_) => include_fallback_bytes(), // e.g. embedded default asset
}

Prevention

When it happens

Trigger: Requesting a path on web that wasn't included in the system data bundle at build time; a path that doesn't match the trimmed key (paths are stripped of the ../data/system/ prefix); reading player-saved files through slurp_file instead of the player storage API.

Common situations: Adding new data files to the repo without rebuilding the web bundle; typos in the path or case-sensitivity differences; trying to read a user-generated file that only lives in localStorage.

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/fd298db872ba58a8. Report an issue: GitHub.

Appendix: source

Thrown at abstio/src/io_web.rs:101

pub fn slurp_file<I: AsRef<str>>(path: I) -> Result<Vec<u8>> {
    let path = path.as_ref();

    if let Some(raw) = SYSTEM_DATA.get_file(path.trim_start_matches("../data/system/")) {
        Ok(raw.contents().to_vec())
    } else if path.starts_with(&path_player("")) {
        let string = read_local_storage(path)?;
        // TODO Hack: if it probably wasn't written with write_json, do the base64 decoding. This
        // may not always be appropriate...
        if path.ends_with(".json") {
            Ok(string.into_bytes())
        } else {
            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

View on GitHub (pinned to 0964f29315)