{"record":{"id":"a83a236f57b62ea3","repo":"gohugoio/hugo","slug":"webp-animated-image-has-no-frames","errorCode":null,"errorMessage":"webp: animated image has no frames","messagePattern":"webp: animated image has no frames","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/warpc/webp.go","lineNumber":273,"sourceCode":"\tvar (\n\t\tbounds         = img.Bounds()\n\t\timageBytes     []byte\n\t\tstride         int\n\t\tframeDurations []int\n\t\tloopCount      int\n\t\tcommand        string\n\t)\n\n\tswitch v := img.(type) {\n\tcase *image.RGBA:\n\t\timageBytes = v.Pix\n\t\tstride = v.Stride\n\t\tcommand = commandEncodeNRGBA\n\tcase *AnimatedImage:\n\t\t// Animated WebP.\n\t\tframes := v.GetFrames()\n\t\tif len(frames) == 0 {\n\t\t\treturn errors.New(\"webp: animated image has no frames\")\n\t\t}\n\t\tfirstFrame := frames[0]\n\t\tbounds = firstFrame.Bounds()\n\t\tnrgba := convertToNRGBA(firstFrame)\n\t\tframeSize := nrgba.Stride * bounds.Dy()\n\t\timageBytes = make([]byte, frameSize*len(frames))\n\t\tstride = nrgba.Stride\n\t\tfor i, frame := range frames {\n\t\t\tvar nrgbaFrame *image.NRGBA\n\t\t\tif i == 0 {\n\t\t\t\tnrgbaFrame = nrgba\n\t\t\t} else {\n\t\t\t\tnrgbaFrame = convertToNRGBA(frame)\n\t\t\t}\n\t\t\tcopy(imageBytes[i*frameSize:(i+1)*frameSize], nrgbaFrame.Pix)\n\t\t}\n\t\tframeDurations = v.GetFrameDurations()\n\t\tloopCount = v.loopCount","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/internal/warpc/webp.go#L255-L291","documentation":"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.","triggerScenarios":"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.","commonSituations":"A GIF/animated source that decoded to zero frames (corrupt or truncated animation), or a programmatic AnimatedImage construction that skipped frame insertion.","solutions":["Validate len(img.GetFrames()) > 0 before calling Encode.","Re-decode the source animation from the original file; a truncated download can yield zero frames.","Fall back to single-frame encoding when the animation is actually a still."],"exampleFix":"// before\nerr := webpCodec.Encode(w, animImg, nil)\n// after\nif len(animImg.GetFrames()) == 0 {\n    return errors.New(\"cannot encode: animation has no frames\")\n}\nerr := webpCodec.Encode(w, animImg, nil)","handlingStrategy":"type-guard","validationCode":"// Check frames before encoding an *AnimatedImage.\nif a, ok := img.(*AnimatedImage); ok && len(a.GetFrames()) == 0 {\n    return errors.New(\"skip: animation has no frames\")\n}","typeGuard":"func hasFrames(a *AnimatedImage) bool { return len(a.GetFrames()) > 0 }","tryCatchPattern":null,"preventionTips":["Validate frame count right after decoding the animation.","Re-decode from the original file if frames are missing.","Fall back to single-frame encode for stills."],"tags":["webp","image","animated","codec"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}