{"record":{"id":"d5cfed0498a57cc6","repo":"a-b-street/abstreet","slug":"missing-from-local-storage","errorCode":null,"errorMessage":"{} missing from local storage","messagePattern":"(.+?) missing from local storage","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"abstio/src/io_web.rs","lineNumber":178,"sourceCode":"    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;\n","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/abstio/src/io_web.rs#L160-L196","documentation":"read_local_storage returns this error when storage.get_item(&path) succeeds but yields None, i.e. the requested key does not exist in localStorage. The message includes the path so the developer knows which key was missing. This is the normal 'not found' outcome of the localStorage API surfaced as an anyhow error.","triggerScenarios":"Calling abstio::slurp_file or maybe_read_binary for a path that was never written to localStorage on this origin/browser profile, or after the user cleared site data; also when the key name casing/format differs from what write_raw stored.","commonSituations":"First run of the app before any save; user cleared browser storage; reading a key written under a different path prefix/version; data lost because localStorage is per-origin and per-browser-profile.","solutions":["Use maybe_read_binary / handle the Err to supply a default value on first run","Seed localStorage (or write defaults) before reading","Verify the exact key path matches what write_raw/write_binary stored","Persist important data server-side or in IndexedDB instead of localStorage to survive storage clears"],"exampleFix":"// before\nlet raw = abstio::slurp_file(path).unwrap(); // panics on first run\n// after\nlet raw = abstio::maybe_read_binary(path).unwrap_or_else(|| default_bytes());","handlingStrategy":"fallback","validationCode":"// check existence before reading\nlet exists = web_sys::window().unwrap()\n    .local_storage().unwrap().unwrap()\n    .get_item(path).unwrap().is_some();","typeGuard":null,"tryCatchPattern":"let raw = slurp_file(path).unwrap_or_else(|_| default_contents());","preventionTips":["Use maybe_read_binary to express 'optional' reads idiomatically","Seed defaults on first run instead of assuming prior writes","Keep key paths centralized so write/read paths never drift","Don't rely on localStorage for durable data — it is per-origin and clearable"],"tags":["wasm","localstorage","not-found","first-run"],"backgroundTag":"record-not-found","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"}