gohugoio/hugo · error

gif: number of frame durations does not match number of fram

Error message

gif: number of frame durations does not match number of frames

What it means

When encoding an animated image (that is not already a raw *gif.GIF) to GIF, Hugo pulls the frames and per-frame durations from the AnimatedImage and requires the two slices to be the same length, since each GIF frame needs a delay entry. A mismatch means the source animation's metadata is inconsistent, so encoding aborts rather than guessing durations.

Source

Thrown at resources/images/codec.go:117

		return jpeg.Encode(w, img, &jpeg.Options{Quality: quality})
	case PNG:
		encoder := png.Encoder{CompressionLevel: png.DefaultCompression}
		return encoder.Encode(w, img)
	case GIF:
		if anim, ok := img.(himage.AnimatedImage); ok {
			if g, ok := anim.GetRaw().(*gif.GIF); ok {
				return gif.EncodeAll(w, g)
			}

			// Animated image, but not a GIF. Convert it.
			frames := anim.GetFrames()
			if len(frames) == 0 {
				return gif.Encode(w, img, &gif.Options{NumColors: 256})
			}

			frameDurations := anim.GetFrameDurations()
			if len(frameDurations) != len(frames) {
				return errors.New("gif: number of frame durations does not match number of frames")
			}

			outGif := &gif.GIF{
				Delay: himage.FrameDurationsToGifDelays(frameDurations),
			}

			outGif.LoopCount = anim.GetLoopCount()

			for _, frame := range frames {
				bounds := frame.Bounds()
				palettedImage := image.NewPaletted(bounds, palette.Plan9)
				draw.Draw(palettedImage, palettedImage.Rect, frame, bounds.Min, draw.Src)
				outGif.Image = append(outGif.Image, palettedImage)
			}

			return gif.EncodeAll(w, outGif)
		}
		return gif.Encode(w, img, &gif.Options{

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Re-encode the source animation with a standard tool (e.g. `ffmpeg` or `img2webp`) so every frame carries a duration, then rebuild.
  2. Convert the asset to GIF outside Hugo and use the GIF directly as the source.
  3. If a well-formed file reproduces this, file a Hugo issue with the source image attached.
Defensive patterns

Strategy: validation

Validate before calling

// For animated gif encoding, ensure durations align with frames
if len(g.Delay) != len(g.Image) {
    return fmt.Errorf("gif frame/delay mismatch: %d delays vs %d frames", len(g.Delay), len(g.Image))
}

Try / catch

if err != nil && strings.Contains(err.Error(), "number of frame durations") {
    // malformed animated gif source — re-export the asset or drop animation
}

Prevention

When it happens

Trigger: Converting an animated source (e.g. animated WebP decoded via the WASM codec) to GIF output — `.Resize "300x gif"` or setting the target format to gif on an animated image whose decoded frame-duration list doesn't match its frame list.

Common situations: Malformed or unusually-authored animated WebP/AVIF files with truncated timing metadata; edge-case files produced by online GIF/WebP converters; codec bugs surfaced after the v0.153.0 image pipeline rework.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/ca3f2a7f8bc9cf21.json. Report an issue: GitHub ↗.