{"record":{"id":"6a64c270942cbaca","repo":"zed-industries/zed","slug":"gif-could-not-be-decoded-all-frames-failed","errorCode":null,"errorMessage":"GIF could not be decoded: all frames failed","messagePattern":"GIF could not be decoded: all frames failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui/src/platform.rs","lineNumber":2773,"sourceCode":"        Self::iter()\n            .find(|format| format.mime_type() == mime_type)\n            .or_else(|| Self::from_mime_type_alias(mime_type))\n    }\n\n    /// Non-canonical mime types that some producers use in the wild.\n    /// Unlike `mime_type()` which returns the single canonical form,\n    /// these are legacy or shortened variants we still need to recognize.\n    fn from_mime_type_alias(mime_type: &str) -> Option<Self> {\n        match mime_type {\n            \"image/jpg\" => Some(Self::Jpeg),\n            \"image/tif\" => Some(Self::Tiff),\n            _ => None,\n        }\n    }\n}\n\n/// An image, with a format and certain bytes\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct Image {\n    /// The image format the bytes represent (e.g. PNG)\n    pub format: ImageFormat,\n    /// The raw image bytes\n    pub bytes: Vec<u8>,\n    /// The unique ID for the image\n    pub id: u64,\n}\n\npub(crate) fn decode_static_image(\n    bytes: &[u8],\n    format: image::ImageFormat,\n) -> Result<SmallVec<[Frame; 1]>> {\n    let decoder = image::ImageReader::with_format(Cursor::new(bytes), format)\n        .into_decoder()\n        .context(\"creating image decoder\")?;\n    decode_static_image_from_decoder(decoder)\n}","sourceCodeStart":2755,"sourceCodeEnd":2791,"githubUrl":"https://github.com/zed-industries/zed/blob/9d272b036335401f339d024ea94968fd51016c40/crates/gpui/src/platform.rs#L2755-L2791","documentation":"When decoding an animated image, each GIF frame is decoded individually and frames that error are skipped with a debug log. If every frame fails, the collected frame list is empty and the decoder bails — the file exists and is classified as GIF, but no frame could be produced (corrupt, truncated, or using constructs the image decoder rejects).","triggerScenarios":"Loading a truncated GIF (interrupted download), a corrupt file, or a GIF whose frames all hit decode errors, leaving the frames vector empty after the loop.","commonSituations":"Broken avatars or emoji fetched over flaky networks; partially-written cache files; an HTML error page saved with a .gif extension; GIFs re-encoded by lossy pipelines.","solutions":["Verify the file is a complete, real GIF (open in a browser, or run 'file icon.gif')","Re-download or re-encode the asset (ffmpeg or gifsicle) if it is corrupt","Treat decode failure as non-fatal: log, show a placeholder or first-frame fallback, and continue rendering"],"exampleFix":"// before: caller assumes decode always succeeds\nlet frames = image.frames()?;\n\n// after: degrade gracefully on all-frames-failed\nlet frames = match image.frames() {\n    Ok(frames) => frames,\n    Err(err) => {\n        log::warn!(\"animated image decode failed: {err}\");\n        return render_placeholder(image.id());\n    }\n};","handlingStrategy":"try-catch","validationCode":"// cheap pre-check before decoding a downloaded asset\nfn looks_like_complete_gif(bytes: &[u8]) -> bool {\n    bytes.starts_with(b\"GIF8\") && bytes.ends_with(&[0x3b]) // GIF trailer byte\n}","typeGuard":null,"tryCatchPattern":"match image.frames() {\n    Ok(frames) => render(frames),\n    Err(err) => {\n        log::warn!(\"animated decode failed: {err}\");\n        render_placeholder() // never propagate into the render loop\n    }\n}","preventionTips":["Validate downloaded images (magic bytes, content-type) before caching them","Keep decode failures non-fatal in UI: placeholder plus log","Re-encode user-supplied GIFs through a sanitizer on ingest"],"tags":["gpui","image","gif","decoding","assets"],"backgroundTag":"image-decode-failed","analyzedSha":"9d272b036335401f339d024ea94968fd51016c40","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}