d2lang/d2 · error
decoded gif image could not be cast as *image.Paletted
Error message
decoded gif image could not be cast as *image.Paletted
What it means
After re-encoding each PNG frame through gif.Encode, xgif decodes it again expecting the result to be an *image.Paletted, which the standard library's gif decoder normally returns. If the decoded image is not *image.Paletted, the animation builder cannot use it for palette-indexed GIF frames and returns this error.
Source
Thrown at lib/xgif/xgif.go:144
i := i
g.Go(func() error {
pngImage := pngImgs[i]
// 1. convert the PNG into a GIF compatible image (Bitmap) by quantizing it to 255 colors
buf := bytes.NewBuffer(nil)
err := gif.Encode(buf, pngImage, &gif.Options{
NumColors: 256, // GIFs can have up to 256 colors
Quantizer: quantize.MedianCutQuantizer{},
})
if err != nil {
return err
}
gifImg, err := gif.Decode(buf)
if err != nil {
return err
}
palettedImg, ok := gifImg.(*image.Paletted)
if !ok {
return fmt.Errorf("decoded gif image could not be cast as *image.Paletted")
}
// 2. make GIF frames of the same size, keeping images centered and with a white background
bounds := pngImage.Bounds()
top := (height - bounds.Dy()) / 2
bottom := top + bounds.Dy()
left := (width - bounds.Dx()) / 2
right := left + bounds.Dx()
var bgIndex int
if len(palettedImg.Palette) == 256 {
bgIndex = findWhiteIndex(palettedImg.Palette)
palettedImg.Palette[bgIndex] = BG_COLOR
} else {
bgIndex = len(palettedImg.Palette)
palettedImg.Palette = append(palettedImg.Palette, BG_COLOR)
}
frame := image.NewPaletted(image.Rect(0, 0, width, height), palettedImg.Palette)View on GitHub (pinned to 0d69dca6f5)
Solutions
- Ensure the standard library image/gif decoder is used (no custom RegisterFormat overrides for GIF)
- Verify the bytes being decoded are the GIF produced by gif.Encode immediately above
- Update Go to a current version; a change in gif.Decode return type would be a stdlib anomaly
- If reproducing, inspect gifImg's concrete type via %T and file a bug
Example fix
gifImg, err := gif.Decode(buf)
if err != nil { return err }
palettedImg, ok := gifImg.(*image.Paletted)
if !ok {
return fmt.Errorf("decoded gif image could not be cast as *image.Paletted (got %T)", gifImg)
} Defensive patterns
Strategy: try-catch
Type guard
palettedImg, ok := gifImg.(*image.Paletted)
if !ok {
return fmt.Errorf("unexpected decoded frame type %T", gifImg)
} Try / catch
if err := pngsToGif(frames, opts); err != nil {
if strings.Contains(err.Error(), "could not be cast as *image.Paletted") {
return retryWithStandardDecoder(frames)
}
return err
} Prevention
- Don't register custom decoders for the GIF format via image.RegisterFormat
- Use the standard library image/gif package unchanged
- Keep Go toolchain current
- Log the concrete type (%T) when this occurs to diagnose decoder interference
When it happens
Trigger: gif.Decode returns an image type other than *image.Paletted — practically only if the standard library behavior changes, the buffer was altered between encode and decode, or a custom decoder is registered for the GIF format that returns a different image type.
Common situations: Building with a modified or nonstandard image/gif package; a GIF registered via image.RegisterFormat overriding decoding; extremely exotic inputs to the xgif conversion API.
Related errors
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/8a0e668bf2652b16.
Report an issue: GitHub.