{"record":{"id":"17ab3d664991cf1a","repo":"a-b-street/abstreet","slug":"failed-to-load-svg-from-bytes-cache-key","errorCode":null,"errorMessage":"Failed to load svg from bytes. cache_key: {}","messagePattern":"Failed to load svg from bytes\\. cache_key: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"widgetry/src/widgets/image.rs","lineNumber":46,"sourceCode":"    /// UTF-8 encoded bytes of an SVG\n    Bytes { bytes: &'a [u8], cache_key: &'a str },\n\n    /// Previously rendered graphics, in the form of a [`GeomBatch`], can\n    /// be packaged as an `Image`.\n    GeomBatch(GeomBatch, geom::Bounds),\n}\n\nimpl ImageSource<'_> {\n    /// Process `self` into a [`GeomBatch`].\n    ///\n    /// The underlying implementation makes use of caching to avoid re-parsing SVGs.\n    pub fn load(&self, prerender: &crate::Prerender) -> (GeomBatch, geom::Bounds) {\n        use crate::svg;\n        match self {\n            ImageSource::Path(image_path) => svg::load_svg(prerender, image_path),\n            ImageSource::Bytes { bytes, cache_key } => {\n                svg::load_svg_bytes(prerender, cache_key, bytes).unwrap_or_else(|_| {\n                    panic!(\"Failed to load svg from bytes. cache_key: {}\", cache_key)\n                })\n            }\n            ImageSource::GeomBatch(geom_batch, bounds) => (geom_batch.clone(), *bounds),\n        }\n    }\n}\n\nimpl<'a, 'c> Image<'a, 'c> {\n    /// An `Image` with no renderable content. Useful for starting a template for creating\n    /// several similar images using a builder pattern.\n    pub fn empty() -> Self {\n        Self {\n            ..Default::default()\n        }\n    }\n\n    /// Create an SVG `Image`, read from `filename`, which is colored to match `Style.icon_fg`\n    pub fn from_path(filename: &'a str) -> Self {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/widgetry/src/widgets/image.rs#L28-L64","documentation":"widgetry's Image widget loads SVG images from a source; when the source is raw bytes, `load` calls `svg::load_svg_bytes` and panics if parsing fails, including the cache_key to identify which image broke. The library treats an unloadable SVG as a programming error rather than a recoverable failure.","triggerScenarios":"Calling `ImageSource::Bytes { bytes, cache_key }` with bytes that are not valid SVG (empty bytes, PNG/JPEG data, truncated or malformed XML) and then calling `Image::load`/`Widget::draw` during prerender.","commonSituations":"Embedding an image downloaded at runtime that turned out to be a raster format; a build script or template produced empty/malformed SVG bytes; file extension and actual content disagree.","solutions":["Verify the bytes are well-formed SVG (e.g. parse with an XML/SVG parser) before constructing ImageSource::Bytes","Ensure the source file is actually SVG (starts with <svg or <?xml), not PNG/JPEG","Check that the file was fully read/truncated correctly (compare byte length)","Use ImageSource::Path instead of Bytes so the path appears in the failure and existing load path is used","Log the cache_key and first bytes of the input to identify the bad source"],"exampleFix":"// before\nImage::from_bytes(cache_key, std::fs::read(path)?)\n// after\nlet bytes = std::fs::read(path)?;\nassert!(String::from_utf8_lossy(&bytes).contains(\"<svg\"), \"{} is not SVG\", path.display());\nImage::from_bytes(cache_key, bytes)","handlingStrategy":"validation","validationCode":"fn is_valid_svg(bytes: &[u8]) -> bool {\n    let s = String::from_utf8_lossy(bytes);\n    s.contains(\"<svg\") && !bytes.is_empty()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only feed SVG content to ImageSource::Bytes; decode/convert raster images first","Include a meaningful cache_key so failures are diagnosable","Validate assets at build time rather than runtime"],"tags":["rust","svg","panic","widgetry"],"backgroundTag":"invalid-argument-format","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"}