a-b-street/abstreet · error
Failed to load svg from bytes. cache_key
Error message
Failed to load svg from bytes. cache_key: {} What it means
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.
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
Example fix
// before
Image::from_bytes(cache_key, std::fs::read(path)?)
// after
let bytes = std::fs::read(path)?;
assert!(String::from_utf8_lossy(&bytes).contains("<svg"), "{} is not SVG", path.display());
Image::from_bytes(cache_key, bytes) Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_svg(bytes: &[u8]) -> bool {
let s = String::from_utf8_lossy(bytes);
s.contains("<svg") && !bytes.is_empty()
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Can't delete ; it's not in the World
- Can't delete mid-drag
- error loading svg
- 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/17ab3d664991cf1a.
Report an issue: GitHub.
Appendix: source
Thrown at widgetry/src/widgets/image.rs:46
/// UTF-8 encoded bytes of an SVG
Bytes { bytes: &'a [u8], cache_key: &'a str },
/// Previously rendered graphics, in the form of a [`GeomBatch`], can
/// be packaged as an `Image`.
GeomBatch(GeomBatch, geom::Bounds),
}
impl ImageSource<'_> {
/// Process `self` into a [`GeomBatch`].
///
/// The underlying implementation makes use of caching to avoid re-parsing SVGs.
pub fn load(&self, prerender: &crate::Prerender) -> (GeomBatch, geom::Bounds) {
use crate::svg;
match self {
ImageSource::Path(image_path) => svg::load_svg(prerender, image_path),
ImageSource::Bytes { bytes, cache_key } => {
svg::load_svg_bytes(prerender, cache_key, bytes).unwrap_or_else(|_| {
panic!("Failed to load svg from bytes. cache_key: {}", cache_key)
})
}
ImageSource::GeomBatch(geom_batch, bounds) => (geom_batch.clone(), *bounds),
}
}
}
impl<'a, 'c> Image<'a, 'c> {
/// An `Image` with no renderable content. Useful for starting a template for creating
/// several similar images using a builder pattern.
pub fn empty() -> Self {
Self {
..Default::default()
}
}
/// Create an SVG `Image`, read from `filename`, which is colored to match `Style.icon_fg`
pub fn from_path(filename: &'a str) -> Self {View on GitHub (pinned to 0964f29315)