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

set_item for failed for encoded length

Error message

set_item for {path} failed for encoded length {}

What it means

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.

Solutions

  1. Reduce the size of the data written, or split it across multiple keys
  2. Use IndexedDB / OPFS instead of localStorage for large or binary data
  3. Detect quota errors (err.name == 'QuotaExceededError') and prompt the user to free space or fall back to a download
  4. Check encoded length before writing: base64 length ~4/3 of bytes; warn if near 5MB

Example fix

// before
abstio::write_binary(path, big_bytes); // may blow the 5MB quota
// after
if big_bytes.len() * 4 / 3 > 4_000_000 {
    // store via IndexedDB or offer a file download instead
} else {
    abstio::write_binary(path, big_bytes);
}
Defensive patterns

Strategy: validation

Validate before calling

const LIMIT: usize = 4_000_000; // stay under ~5MB localStorage quota after base64
fn fits_local_storage(bytes: &[u8]) -> bool { bytes.len() * 4 / 3 <= LIMIT }

Try / catch

match write_result {
    Ok(()) => (),
    Err(e) if e.to_string().contains("QuotaExceeded") || e.to_string().contains("set_item") => {
        // free space, split data, or switch to IndexedDB
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/16acc92e1c6e84ee. Report an issue: GitHub.

Appendix: source

Thrown at abstio/src/io_web.rs:146

}

pub fn write_binary<T: Serialize>(path: String, obj: &T) {
    write_raw(path, &abstutil::to_binary(obj)).unwrap();
}

pub fn write_raw(path: String, bytes: &[u8]) -> Result<()> {
    // Only save for data/player, for now
    if !path.starts_with(&path_player("")) {
        bail!("Not saving {}", path);
    }

    let window = web_sys::window().unwrap();
    let storage = window.local_storage().unwrap().unwrap();
    // Local storage only supports strings, so base64 encoding needed
    use base64::Engine;
    let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
    storage.set_item(&path, &encoded).map_err(|err| {
        anyhow!(err.as_string().unwrap_or_else(|| format!(
            "set_item for {path} failed for encoded length {}",
            encoded.len()
        )))
    })?;
    Ok(())
}

pub fn delete_file<I: AsRef<str>>(path: I) {
    let path = path.as_ref();
    if !path.starts_with(&path_player("")) {
        warn!("Not deleting {}", path);
        return;
    }
    let window = web_sys::window().unwrap();
    let storage = window.local_storage().unwrap().unwrap();
    storage.remove_item(path).unwrap();
}

View on GitHub (pinned to 0964f29315)