gohugoio/hugo · error

decoded AVIF buffer size %d is not a multiple of frame size

Error message

decoded AVIF buffer size %d is not a multiple of frame size %d

What it means

Raised in AvifCodec.Decode (internal/warpc/avif.go:162) when decoding an animated AVIF. The decoder computes frameSize = stride * height and expects the blob returned by the WASM libavif module to contain an exact whole number of frames; if the buffer length isn't a multiple of the frame size (or frame size is 0), the pixel data can't be split into frames and Hugo aborts the decode.

Source

Thrown at internal/warpc/avif.go:162

		}
	}

	if len(out.Data.Params.FrameDurations) > 0 {
		img := &AnimatedImage{
			frameDurations:          out.Data.Params.FrameDurations,
			loopCount:               avifLoopCountToGo(out.Data.Params.LoopCount),
			depth:                   depth,
			colorPrimaries:          out.Data.Params.ColorPrimaries,
			transferCharacteristics: out.Data.Params.TransferCharacteristics,
			matrixCoefficients:      out.Data.Params.MatrixCoefficients,
			maxCLL:                  out.Data.Params.MaxCLL,
			maxPALL:                 out.Data.Params.MaxPALL,
		}

		frameSize := stride * h
		pixLen := len(destination.Bytes())
		if frameSize == 0 || pixLen%frameSize != 0 {
			return nil, fmt.Errorf("decoded AVIF buffer size %d is not a multiple of frame size %d", pixLen, frameSize)
		}
		frameCount := pixLen / frameSize
		if frameCount != len(out.Data.Params.FrameDurations) {
			return nil, fmt.Errorf("decoded AVIF frame count %d does not match frame durations %d", frameCount, len(out.Data.Params.FrameDurations))
		}
		frames := make([]image.Image, frameCount)
		for i := range frames {
			frameBytes := destination.Bytes()[i*frameSize : (i+1)*frameSize]
			if isHDR {
				// NRGBA64 for HDR - libavif returns non-premultiplied alpha.
				frameImg := &image.NRGBA64{
					Pix:    frameBytes,
					Stride: stride,
					Rect:   image.Rect(0, 0, w, h),
				}
				frames[i] = frameImg
			} else {
				// NRGBA - libavif returns non-premultiplied alpha.

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Re-encode the animated AVIF with a standard tool (avifenc/ffmpeg) and constant frame dimensions.
  2. Verify the file plays correctly in a browser to rule out corruption.
  3. As a workaround, convert the asset to animated WebP or GIF for Hugo processing.
  4. If reproducible with a valid file, report it to Hugo with the file attached — it indicates a decoder protocol bug.
Defensive patterns

Strategy: try-catch

Try / catch

img, err := decodeAVIF(buf)
if err != nil {
    // indicates a truncated/corrupt AVIF or a decoder bug — surface, don't mask
    return fmt.Errorf("corrupt AVIF %s: %w", path, err)
}

Prevention

When it happens

Trigger: Decoding an animated AVIF (Params.FrameDurations non-empty) where the raw pixel blob streamed back from the WASM module has a length not divisible by stride*height — indicating a truncated blob transfer, an HDR/8-bit depth mismatch in stride accounting, or a corrupt animation.

Common situations: Corrupted/truncated animated AVIF files; animated AVIFs with unusual per-frame geometry or produced by nonstandard encoders; edge cases in HDR (10/12-bit) animated AVIFs where 16-bit output changes buffer size expectations.

Related errors


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