{"record":{"id":"0af740c9de42fc0c","repo":"a-b-street/abstreet","slug":"no-local-storage","errorCode":null,"errorMessage":"no local_storage?","messagePattern":"no local_storage\\?","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"abstio/src/io_web.rs","lineNumber":174,"sourceCode":"    if !path.starts_with(&path_player(\"\")) {\n        warn!(\"Not deleting {}\", path);\n        return;\n    }\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","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/abstio/src/io_web.rs#L156-L192","documentation":"read_local_storage expects window.local_storage() to return Some(Storage); a None means the browser gave no storage object for this origin. The library turns that into the \"no local_storage?\" error. This is separate from a failed call or a missing key.","triggerScenarios":"Calling read_local_storage (via slurp_file/maybe_read_binary) in a context where window.local_storage() resolves to None — e.g. storage disabled for the origin, certain privacy modes, or insecure/embedded contexts where the browser suppresses localStorage.","commonSituations":"Safari older private-browsing sessions where localStorage appears absent; embedded webviews with WebStorage disabled; origins with storage partitioned away.","solutions":["Treat localStorage as optional: fall back to in-memory or IndexedDB storage","Detect the condition up front with web_sys::window().and_then(|w| w.local_storage().ok().flatten()) before using the library API","Enable storage for the webview/origin in the embedding application","Inform the user that saving requires enabling site data"],"exampleFix":"// before\nlet raw = abstio::slurp_file(path).expect(\"storage\");\n// after\nlet has_storage = web_sys::window()\n    .and_then(|w| w.local_storage().ok().flatten())\n    .is_some();\nlet raw = if has_storage { abstio::slurp_file(path)? } else { default_value() };","handlingStrategy":"fallback","validationCode":"let has_storage = web_sys::window()\n    .and_then(|w| w.local_storage().ok().flatten())\n    .is_some();","typeGuard":"fn local_storage_available() -> bool {\n    web_sys::window().and_then(|w| w.local_storage().ok().flatten()).is_some()\n}","tryCatchPattern":"let raw = if local_storage_available() {\n    slurp_file(path).unwrap_or_default()\n} else {\n    in_memory_store().get(path).cloned().unwrap_or_default()\n};","preventionTips":["Treat localStorage as optional and pick a backend at startup","Enable WebStorage in embedded webview configurations","Test in private-browsing modes where storage may be absent","Cache data in memory so a missing Storage object degrades gracefully"],"tags":["wasm","localstorage","browser","storage-disabled"],"backgroundTag":"missing-dependency","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"}