{"record":{"id":"3229faca251a4b25","repo":"a-b-street/abstreet","slug":"error-loading-svg","errorCode":null,"errorMessage":"error loading svg: {}","messagePattern":"error loading svg: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"widgetry/src/svg.rs","lineNumber":30,"sourceCode":"pub const HIGH_QUALITY: f32 = 0.01;\npub const LOW_QUALITY: f32 = 1.0;\n\n// Code here adapted from\n// https://github.com/nical/lyon/blob/0d0ee771180fb317b986d9cf30266722e0773e01/examples/wgpu_svg/src/main.rs\n\npub fn load_svg(prerender: &Prerender, filename: &str) -> (GeomBatch, Bounds) {\n    let cache_key = format!(\"file://{}\", filename);\n    if let Some(pair) = prerender.assets.get_cached_svg(&cache_key) {\n        return pair;\n    }\n\n    let bytes = (prerender.assets.read_svg)(filename);\n    load_svg_from_bytes_uncached(&bytes)\n        .map(|(batch, bounds)| {\n            prerender.assets.cache_svg(cache_key, batch.clone(), bounds);\n            (batch, bounds)\n        })\n        .unwrap_or_else(|_| panic!(\"error loading svg: {}\", filename))\n}\n\npub fn load_svg_bytes(\n    prerender: &Prerender,\n    cache_key: &str,\n    bytes: &[u8],\n) -> anyhow::Result<(GeomBatch, Bounds)> {\n    let cache_key = format!(\"bytes://{}\", cache_key);\n    if let Some(pair) = prerender.assets.get_cached_svg(&cache_key) {\n        return Ok(pair);\n    }\n\n    load_svg_from_bytes_uncached(bytes).map(|(batch, bounds)| {\n        prerender.assets.cache_svg(cache_key, batch.clone(), bounds);\n        (batch, bounds)\n    })\n}\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/widgetry/src/svg.rs#L12-L48","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet bytes = std::fs::read(\"assets/map.svg\").unwrap();\n// after\nassert!(std::fs::read(\"assets/map.svg\")?.starts_with(b\"<\"), \"map.svg is not SVG\");","handlingStrategy":"validation","validationCode":"// Check the asset parses before calling load_svg\nlet bytes = std::fs::read(path)?;\nassert!(!bytes.is_empty(), \"{} is empty\", path);\nusvg::Tree::from_str(&String::from_utf8_lossy(&bytes), &usvg::Options::default()).expect(\"invalid svg\");","typeGuard":null,"tryCatchPattern":"match load_svg_bytes(prerender, key, &bytes) { Ok(b) => b, Err(_) => default_batch }","preventionTips":["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"],"tags":["rust","svg","parsing","panic"],"backgroundTag":"xml-parse-error","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"}