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

get_item failed

Error message

get_item failed

What it means

read_local_storage maps a failure of storage.get_item(&path) to the exception's message, falling back to "get_item failed" when the DomException carries no string. The key lookup itself threw rather than returning None. In practice this is rare, since get_item usually returns Ok(None) for missing keys.

Solutions

  1. Retry the read once, then fall back to defaults — the condition is often transient
  2. Log err.name/err.as_string() to identify the exact DomException
  3. Fall back to an in-memory cache or refetch from the network
  4. Ask the user to re-enable site data if a security exception persists

Example fix

// before
let raw = abstio::slurp_file(path).unwrap();
// after
let raw = match abstio::slurp_file(path) {
    Ok(r) => r,
    Err(e) => { log::warn!("get_item failed: {e}"); Default::default() }
};
Defensive patterns

Strategy: try-catch

Try / catch

let raw = match slurp_file(path) {
    Ok(v) => v,
    Err(e) => {
        log::warn!("get_item failed: {e}; using default");
        Default::default()
    }
};

Prevention

When it happens

Trigger: Calling read_local_storage (via slurp_file/maybe_read_binary) when storage.get_item throws — e.g. storage became unavailable mid-session, a security exception after privacy settings changed, or corrupted origin storage state.

Common situations: Browser storage detached mid-session (privacy mode toggled); extensions interfering with storage access; quota/security exceptions surfacing at read time.

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

Appendix: source

Thrown at abstio/src/io_web.rs:177

    }
    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());
    }
    keys
}

/// Returns path on success
pub fn write_file(path: String, contents: String) -> Result<String> {
    // Make the browser prompt the user to save a local file with arbitrary contents.
    use wasm_bindgen::JsCast;

View on GitHub (pinned to 0964f29315)