a-b-street/abstreet · error · anyhow::Error

local_storage failed

Error message

local_storage failed

What it means

read_local_storage maps a failure of window.local_storage() to the underlying exception's text, falling back to "local_storage failed" when the DomException has no message. This means the browser refused or failed the attempt to access the localStorage object itself. It is distinct from the key simply being missing.

Solutions

  1. Ask the user to enable cookies/site data / disable the blocking extension for the site
  2. Avoid sandboxed iframes or add allow-same-origin to the sandbox attribute
  3. Log the underlying exception message (err.as_string()) to diagnose which exception occurred
  4. Fall back to in-memory storage or IndexedDB when localStorage is unavailable

Example fix

// before
let raw = abstio::slurp_file(path).unwrap();
// after
let raw = abstio::slurp_file(path).unwrap_or_else(|e| {
    warn!("localStorage unavailable ({e}); using defaults");
    String::new()
});
Defensive patterns

Strategy: try-catch

Validate before calling

let storage_ok = web_sys::window()
    .and_then(|w| w.local_storage().ok())
    .transpose()
    .is_ok();

Try / catch

match slurp_file(path) {
    Ok(v) => v,
    Err(e) => { log::warn!("storage access failed: {e}"); Default::default() }
}

Prevention

When it happens

Trigger: Calling read_local_storage (via slurp_file/maybe_read_binary) when window.local_storage() returns Err — e.g. cookies/site-data blocked, storage access denied by browser privacy settings, or the page opened in a context where storage is disabled (some private-browsing modes in older browsers).

Common situations: Users with strict privacy settings or extensions blocking storage; sandboxed iframes without allow-same-origin; embedded webviews with storage disabled.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at abstio/src/io_web.rs:170

}

pub fn delete_file<I: AsRef<str>>(path: I) {
    let path = path.as_ref();
    if !path.starts_with(&path_player("")) {
        warn!("Not deleting {}", path);
        return;
    }
    let window = web_sys::window().unwrap();
    let storage = window.local_storage().unwrap().unwrap();
    storage.remove_item(path).unwrap();
}

fn read_local_storage(path: &str) -> Result<String> {
    let window = web_sys::window().ok_or(anyhow!("no window?"))?;
    let storage = window
        .local_storage()
        .map_err(|err| {
            anyhow!(err
                .as_string()
                .unwrap_or("local_storage failed".to_string()))
        })?
        .ok_or(anyhow!("no local_storage?"))?;
    let string = storage
        .get_item(&path)
        .map_err(|err| anyhow!(err.as_string().unwrap_or("get_item failed".to_string())))?
        .ok_or(anyhow!("{} missing from local storage", path))?;
    Ok(string)
}

fn list_local_storage_keys() -> Vec<String> {
    let window = web_sys::window().unwrap();
    let storage = window.local_storage().unwrap().unwrap();
    let mut keys = Vec::new();
    for idx in 0..storage.length().unwrap() {
        keys.push(storage.key(idx).unwrap().unwrap());
    }

View on GitHub (pinned to 0964f29315)