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
- Re-encode the animated AVIF with a standard tool (avifenc/ffmpeg) and constant frame dimensions.
- Verify the file plays correctly in a browser to rule out corruption.
- As a workaround, convert the asset to animated WebP or GIF for Hugo processing.
- 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
- Verify AVIF files aren't truncated (checksum or re-download) before feeding them to the pipeline
- Keep the WASM decoder (warpc runtime) up to date; buffer-size mismatch usually means version skew or corruption
- Fail the single asset with a clear filename in the error rather than aborting silently
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
- received invalid image dimensions: %dx%d stride %d
- timeout
- imaging.avif.hint must be one of picture, photo, drawing, ic
- imaging.avif.encoderSpeed must be between 1 and 10, got %d
- ErrShutdown
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/d04097f288a49bed.json.
Report an issue: GitHub ↗.