gohugoio/hugo · error

webp: animated image has no frames

Error message

webp: animated image has no frames

What it means

Returned by WebpCodec.Encode in internal/warpc/webp.go:273 for the concrete *AnimatedImage type when GetFrames() returns an empty slice. The encoder needs at least one frame to derive bounds/stride before dispatching the encode command to WASM.

Solutions

  1. Validate len(img.GetFrames()) > 0 before calling Encode.
  2. Re-decode the source animation from the original file; a truncated download can yield zero frames.
  3. Fall back to single-frame encoding when the animation is actually a still.

Example fix

// before
err := webpCodec.Encode(w, animImg, nil)
// after
if len(animImg.GetFrames()) == 0 {
    return errors.New("cannot encode: animation has no frames")
}
err := webpCodec.Encode(w, animImg, nil)
Defensive patterns

Strategy: type-guard

Validate before calling

// Check frames before encoding an *AnimatedImage.
if a, ok := img.(*AnimatedImage); ok && len(a.GetFrames()) == 0 {
    return errors.New("skip: animation has no frames")
}

Type guard

func hasFrames(a *AnimatedImage) bool { return len(a.GetFrames()) > 0 }

Prevention

When it happens

Trigger: Passing an *AnimatedImage (warpc's own animated type) with zero frames into WebpCodec.Encode. Typically a decode step produced an animated image object whose frame list was never populated or was cleared.

Common situations: A GIF/animated source that decoded to zero frames (corrupt or truncated animation), or a programmatic AnimatedImage construction that skipped frame insertion.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/a83a236f57b62ea3. Report an issue: GitHub.

Appendix: source

Thrown at internal/warpc/webp.go:273

	var (
		bounds         = img.Bounds()
		imageBytes     []byte
		stride         int
		frameDurations []int
		loopCount      int
		command        string
	)

	switch v := img.(type) {
	case *image.RGBA:
		imageBytes = v.Pix
		stride = v.Stride
		command = commandEncodeNRGBA
	case *AnimatedImage:
		// Animated WebP.
		frames := v.GetFrames()
		if len(frames) == 0 {
			return errors.New("webp: animated image has no frames")
		}
		firstFrame := frames[0]
		bounds = firstFrame.Bounds()
		nrgba := convertToNRGBA(firstFrame)
		frameSize := nrgba.Stride * bounds.Dy()
		imageBytes = make([]byte, frameSize*len(frames))
		stride = nrgba.Stride
		for i, frame := range frames {
			var nrgbaFrame *image.NRGBA
			if i == 0 {
				nrgbaFrame = nrgba
			} else {
				nrgbaFrame = convertToNRGBA(frame)
			}
			copy(imageBytes[i*frameSize:(i+1)*frameSize], nrgbaFrame.Pix)
		}
		frameDurations = v.GetFrameDurations()
		loopCount = v.loopCount

View on GitHub (pinned to 52c9bd7908)