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

  1. Ensure the standard library image/gif decoder is used (no custom RegisterFormat overrides for GIF)
  2. Verify the bytes being decoded are the GIF produced by gif.Encode immediately above
  3. Update Go to a current version; a change in gif.Decode return type would be a stdlib anomaly
  4. 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

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.