{"record":{"id":"16acc92e1c6e84ee","repo":"a-b-street/abstreet","slug":"set-item-for-path-failed-for-encoded-length","errorCode":null,"errorMessage":"set_item for {path} failed for encoded length {}","messagePattern":"set_item for (.+?) failed for encoded length (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"abstio/src/io_web.rs","lineNumber":146,"sourceCode":"}\n\npub fn write_binary<T: Serialize>(path: String, obj: &T) {\n    write_raw(path, &abstutil::to_binary(obj)).unwrap();\n}\n\npub fn write_raw(path: String, bytes: &[u8]) -> Result<()> {\n    // Only save for data/player, for now\n    if !path.starts_with(&path_player(\"\")) {\n        bail!(\"Not saving {}\", path);\n    }\n\n    let window = web_sys::window().unwrap();\n    let storage = window.local_storage().unwrap().unwrap();\n    // Local storage only supports strings, so base64 encoding needed\n    use base64::Engine;\n    let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);\n    storage.set_item(&path, &encoded).map_err(|err| {\n        anyhow!(err.as_string().unwrap_or_else(|| format!(\n            \"set_item for {path} failed for encoded length {}\",\n            encoded.len()\n        )))\n    })?;\n    Ok(())\n}\n\npub fn delete_file<I: AsRef<str>>(path: I) {\n    let path = path.as_ref();\n    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","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/abstio/src/io_web.rs#L128-L164","documentation":"On wasm, abstio::write_raw persists bytes to browser localStorage, which only holds strings, so the payload is base64-encoded first. If the storage.set_item call returns a DomException without a readable message, the library formats this fallback message including the key path and encoded length. The most common underlying cause is the ~5MB localStorage quota being exceeded.","triggerScenarios":"Calling abstio::write_binary (or write_path/write_json) on a wasm build where the base64-encoded payload pushes localStorage over the browser quota (typically 5MB), or the key/path is malformed.","commonSituations":"Saving large maps, big simulation results, or base64-inflated binary blobs (+33% size) into the ~5MB browser localStorage limit; users with already-full storage from previous sessions.","solutions":["Reduce the size of the data written, or split it across multiple keys","Use IndexedDB / OPFS instead of localStorage for large or binary data","Detect quota errors (err.name == 'QuotaExceededError') and prompt the user to free space or fall back to a download","Check encoded length before writing: base64 length ~4/3 of bytes; warn if near 5MB"],"exampleFix":"// before\nabstio::write_binary(path, big_bytes); // may blow the 5MB quota\n// after\nif big_bytes.len() * 4 / 3 > 4_000_000 {\n    // store via IndexedDB or offer a file download instead\n} else {\n    abstio::write_binary(path, big_bytes);\n}","handlingStrategy":"validation","validationCode":"const LIMIT: usize = 4_000_000; // stay under ~5MB localStorage quota after base64\nfn fits_local_storage(bytes: &[u8]) -> bool { bytes.len() * 4 / 3 <= LIMIT }","typeGuard":null,"tryCatchPattern":"match write_result {\n    Ok(()) => (),\n    Err(e) if e.to_string().contains(\"QuotaExceeded\") || e.to_string().contains(\"set_item\") => {\n        // free space, split data, or switch to IndexedDB\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep localStorage payloads small (< ~3MB raw bytes)","Use IndexedDB/OPFS for large or binary data","Detect QuotaExceededError and surface a user-facing message","Track cumulative usage across keys, since the quota is per-origin"],"tags":["wasm","localstorage","quota","web-storage"],"backgroundTag":"file-write-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"}