gohugoio/hugo · error

WebPAnimEncoderAdd failed\n

Error message

WebPAnimEncoderAdd failed\n

What it means

Printed inside genwebp's encodeNRGBAAnimated loop (webp.c:243) when WebPAnimEncoderAdd returns false for a regular frame. This means libwebp rejected the frame after the picture was already imported — typically because the WebPConfig is invalid (quality/method out of range, lossless/lossy conflict), the timestamp sequence is non-monotonic, or memory allocation inside the encoder failed. The worker tears down the encoder and returns NULL.

Source

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

            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))
    {
        fprintf(stderr, "WebPAnimEncoderAdd failed for final frame\n");
        WebPAnimEncoderDelete(enc);
        return NULL;
    }

    WebPData webp_data_out;
    WebPDataInit(&webp_data_out);
    if (!WebPAnimEncoderAssemble(enc, &webp_data_out))

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Sanitize params.frameDurations on the Go side: ensure every value is > 0 and that the cumulative timestamp is strictly increasing.
  2. If durations came from a GIF decoder, convert centiseconds to milliseconds consistently and clamp zeros to a small positive default.
  3. Validate WebPConfig fields (quality 1-100, method 0-6, preset resolved from a known hint) before encoding.
  4. For OOM cases, lower resolution or quality, or raise the worker memory limit.
  5. Log the failing frame index and its duration on the Go side to correlate.

Example fix

// before: GIF durations in centiseconds sent raw, some are 0
params.FrameDurations = gifDurations

// after: convert to ms, force strictly positive
for i, d := range gifDurations {
    ms := d * 10
    if ms <= 0 { ms = 100 }
    params.FrameDurations[i] = ms
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure strictly positive, monotonically increasing cumulative timestamps.
func sanitizeDurations(ms []int) []int {
    out := make([]int, len(ms))
    for i, d := range ms {
        if d <= 0 { d = 100 } // default 100ms
        out[i] = d
    }
    return out
}

Prevention

When it happens

Trigger: A frame's timestamp (accumulated from params.frameDurations) is not greater than the previous frame's (a zero or negative duration in the array), the WebPConfig combination is rejected by libwebp internally, or the encoder runs out of memory while compressing a frame.

Common situations: Animated GIF source with a frame that has duration 0 or that was decoded with duration in the wrong unit (centiseconds vs milliseconds producing non-monotonic or huge jumps), a custom WebPConfig the user supplied via Hugo options that libwebp rejects, or a large-frame OOM.

Related errors


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