a-b-street/abstreet · error
error loading svg
Error message
error loading svg: {} What it means
load_svg panics when parsing the SVG bytes (via usvg) fails after reading the asset. The bytes were fetched through the read_svg hook, but usvg::Tree parsing or conversion produced an error, so load_svg_from_bytes_uncached returns Err and load_svg unwraps it into a panic naming the file.
Solutions
- Open the named file and validate it is well-formed SVG XML.
- Check the custom read_svg implementation isn't returning empty bytes on failure.
- Re-export/clean the SVG asset (e.g. resave with Inkscape/plain SVG profile).
- Use load_svg_bytes for tolerant handling if you control the call path.
Example fix
// before
let bytes = std::fs::read("assets/map.svg").unwrap();
// after
assert!(std::fs::read("assets/map.svg")?.starts_with(b"<"), "map.svg is not SVG"); Defensive patterns
Strategy: validation
Validate before calling
// Check the asset parses before calling load_svg
let bytes = std::fs::read(path)?;
assert!(!bytes.is_empty(), "{} is empty", path);
usvg::Tree::from_str(&String::from_utf8_lossy(&bytes), &usvg::Options::default()).expect("invalid svg"); Try / catch
match load_svg_bytes(prerender, key, &bytes) { Ok(b) => b, Err(_) => default_batch } Prevention
- Validate SVG assets in CI (parse each with usvg)
- Never let read_svg swallow errors into empty bytes
- Keep assets as plain SVG, re-export from design tools with simple profiles
When it happens
Trigger: Calling load_svg with a file whose contents are invalid/unparsable SVG: empty file, HTML error page saved as .svg, malformed XML, SVG features usvg rejects, or read_svg returning garbage/empty bytes on failure.
Common situations: Custom read_svg implementations that swallow open errors and return empty Vec (leading to parse failure here), corrupted assets in the repo, downloading assets over a proxy returning HTML.
Related errors
- render_line( )
- curvey( )
- Failed to load svg from bytes. cache_key
- This build of A/B Street stores player data in…
- Can't find the data/ directory
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/3229faca251a4b25.
Report an issue: GitHub.
Appendix: source
Thrown at widgetry/src/svg.rs:30
pub const HIGH_QUALITY: f32 = 0.01;
pub const LOW_QUALITY: f32 = 1.0;
// Code here adapted from
// https://github.com/nical/lyon/blob/0d0ee771180fb317b986d9cf30266722e0773e01/examples/wgpu_svg/src/main.rs
pub fn load_svg(prerender: &Prerender, filename: &str) -> (GeomBatch, Bounds) {
let cache_key = format!("file://{}", filename);
if let Some(pair) = prerender.assets.get_cached_svg(&cache_key) {
return pair;
}
let bytes = (prerender.assets.read_svg)(filename);
load_svg_from_bytes_uncached(&bytes)
.map(|(batch, bounds)| {
prerender.assets.cache_svg(cache_key, batch.clone(), bounds);
(batch, bounds)
})
.unwrap_or_else(|_| panic!("error loading svg: {}", filename))
}
pub fn load_svg_bytes(
prerender: &Prerender,
cache_key: &str,
bytes: &[u8],
) -> anyhow::Result<(GeomBatch, Bounds)> {
let cache_key = format!("bytes://{}", cache_key);
if let Some(pair) = prerender.assets.get_cached_svg(&cache_key) {
return Ok(pair);
}
load_svg_from_bytes_uncached(bytes).map(|(batch, bounds)| {
prerender.assets.cache_svg(cache_key, batch.clone(), bounds);
(batch, bounds)
})
}
View on GitHub (pinned to 0964f29315)