{"record":{"id":"07bdf779798a643c","repo":"a-b-street/abstreet","slug":"get-item-failed","errorCode":null,"errorMessage":"get_item failed","messagePattern":"get_item failed","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"abstio/src/io_web.rs","lineNumber":177,"sourceCode":"    }\n    let window = web_sys::window().unwrap();\n    let storage = window.local_storage().unwrap().unwrap();\n    storage.remove_item(path).unwrap();\n}\n\nfn read_local_storage(path: &str) -> Result<String> {\n    let window = web_sys::window().ok_or(anyhow!(\"no window?\"))?;\n    let storage = window\n        .local_storage()\n        .map_err(|err| {\n            anyhow!(err\n                .as_string()\n                .unwrap_or(\"local_storage failed\".to_string()))\n        })?\n        .ok_or(anyhow!(\"no local_storage?\"))?;\n    let string = storage\n        .get_item(&path)\n        .map_err(|err| anyhow!(err.as_string().unwrap_or(\"get_item failed\".to_string())))?\n        .ok_or(anyhow!(\"{} missing from local storage\", path))?;\n    Ok(string)\n}\n\nfn list_local_storage_keys() -> Vec<String> {\n    let window = web_sys::window().unwrap();\n    let storage = window.local_storage().unwrap().unwrap();\n    let mut keys = Vec::new();\n    for idx in 0..storage.length().unwrap() {\n        keys.push(storage.key(idx).unwrap().unwrap());\n    }\n    keys\n}\n\n/// Returns path on success\npub fn write_file(path: String, contents: String) -> Result<String> {\n    // Make the browser prompt the user to save a local file with arbitrary contents.\n    use wasm_bindgen::JsCast;","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/abstio/src/io_web.rs#L159-L195","documentation":"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.","triggerScenarios":"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.","commonSituations":"Browser storage detached mid-session (privacy mode toggled); extensions interfering with storage access; quota/security exceptions surfacing at read time.","solutions":["Retry the read once, then fall back to defaults — the condition is often transient","Log err.name/err.as_string() to identify the exact DomException","Fall back to an in-memory cache or refetch from the network","Ask the user to re-enable site data if a security exception persists"],"exampleFix":"// before\nlet raw = abstio::slurp_file(path).unwrap();\n// after\nlet raw = match abstio::slurp_file(path) {\n    Ok(r) => r,\n    Err(e) => { log::warn!(\"get_item failed: {e}\"); Default::default() }\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let raw = match slurp_file(path) {\n    Ok(v) => v,\n    Err(e) => {\n        log::warn!(\"get_item failed: {e}; using default\");\n        Default::default()\n    }\n};","preventionTips":["Retry transient storage failures once before giving up","Log the DomException name for diagnosis","Keep a fallback in-memory snapshot of critical values","Re-check storage availability after privacy settings change mid-session"],"tags":["wasm","localstorage","get-item","browser"],"backgroundTag":"file-read-failed","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}