gohugoio/hugo · error

WebPPictureImportRGBA failed\n

Error message

WebPPictureImportRGBA failed\n

What it means

Printed inside genwebp's encodeNRGBAAnimated loop (webp.c:235) when WebPPictureImportRGBA fails for a frame. Unlike the static path (826) this print does not include the error_code, but the cause class is the same: stride < width*4, dimensions over WebP's limit, or a frame buffer that is too short. The worker frees the picture, deletes the anim encoder, and returns NULL.

Source

Thrown at internal/warpc/genwebp/webp.c:235

    for (int i = 0; i < params.frameCount; i++)
    {
        WebPPicture pic;
        if (!WebPPictureInit(&pic))
        {
            fprintf(stderr, "WebPPictureInit failed\n");
            WebPAnimEncoderDelete(enc);
            return NULL;
        }
        pic.use_argb = 1;
        pic.width = params.width;
        pic.height = params.height;

        const uint8_t *frame_rgba = all_frames_data + i * frame_rgba_size;

        if (!WebPPictureImportRGBA(&pic, frame_rgba, params.stride))
        {
            fprintf(stderr, "WebPPictureImportRGBA failed\n");
            WebPPictureFree(&pic);
            WebPAnimEncoderDelete(enc);
            return NULL;
        }

        if (!WebPAnimEncoderAdd(enc, &pic, timestamp, config))
        {
            fprintf(stderr, "WebPAnimEncoderAdd failed\n");
            WebPPictureFree(&pic);
            WebPAnimEncoderDelete(enc);
            return NULL;
        }
        timestamp += params.frameDurations[i];
        WebPPictureFree(&pic);
    }

    if (!WebPAnimEncoderAdd(enc, NULL, timestamp, config))
    {

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Assert on the Go side that len(all_frames_data) == params.stride*params.height*params.frameCount before invoking the animated encoder.
  2. Pin params.stride = params.width*4 and verify each decoded frame is laid out at exactly that stride.
  3. Confirm params.frameCount matches the number of frames actually packed into all_frames_data.
  4. Compare the canvas dimensions used for decoding against those sent for encoding — they must be identical.
  5. Re-decode the source if any frame's stride looks inconsistent.

Example fix

// before: stride mismatch between decoder output and encoder params
params.Stride = w * 3 // wrong for RGBA
enc.Encode(params, frames)

// after
params.Stride = w * 4
if len(frames) != params.Stride*h*params.FrameCount {
    return fmt.Errorf("frame buffer %d != expected %d", len(frames), params.Stride*h*params.FrameCount)
}
enc.Encode(params, frames)
Defensive patterns

Strategy: validation

Validate before calling

func validateAnimFrameBuffer(pix []byte, w, h, stride, frameCount int) error {
    if stride != w*4 { return fmt.Errorf("stride %d != width*4 %d", stride, w*4) }
    need := stride * h * frameCount
    if len(pix) < need { return fmt.Errorf("buffer %d < need %d", len(pix), need) }
    return nil
}

Prevention

When it happens

Trigger: params.stride does not equal params.width*4, frame_rgba_size (params.stride*params.height) exceeds the actual remaining bytes in all_frames_data for a given frame index, or width/height drift between frames (the encoder assumes a fixed canvas size).

Common situations: Animated source decoded with a stride that does not match what the Go host sends in params.stride, frame_count mismatch so frame_index*frame_rgba_size runs past the buffer end, or a canvas-size change between decode and encode that was not propagated to params.

Related errors


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