gohugoio/hugo · error

WebPAnimEncoderAssemble failed\n

Error message

WebPAnimEncoderAssemble failed\n

What it means

Printed by genwebp's encodeNRGBAAnimated (webp.c:263) when WebPAnimEncoderAssemble returns false. Assemble walks the accumulated frames and produces the final RIFF-formatted WebP byte stream; failure indicates an internal encoder error, typically memory allocation failure while building the container, or an encoder that was left in an invalid state. The worker deletes the encoder and returns NULL.

Source

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

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

    *output_size = webp_data_out.size;
    uint8_t *webp_data = malloc(*output_size);
    if (webp_data == NULL)
    {
        fprintf(stderr, "malloc failed for final webp data\n");
        WebPDataClear(&webp_data_out);
        return NULL;
    }
    memcpy(webp_data, webp_data_out.bytes, *output_size);
    WebPDataClear(&webp_data_out);

    return webp_data;
}

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Reduce animation size (fewer frames or smaller canvas) to shrink the assembled output.
  2. Raise the worker memory limit and watch RSS during assemble with /usr/bin/time -v.
  3. Rebuild against a current libwebp and re-test the same input.
  4. If the input is pathological (thousands of tiny frames), pre-coalesce or drop redundant frames before encoding.
  5. Fall back to a non-animated output format for inputs that consistently fail assemble.

Example fix

# before: 500-frame animation, assemble fails OOM in a 128MB container
$ convert big.gif out.webp

# after: raise worker memory and cap frame count
# docker/compose: mem_limit: 1g
# Hugo side: drop frames beyond a cap before encoding
if frameCount > 200 { frames = frames[:200] }
Defensive patterns

Strategy: fallback

Validate before calling

// Cap animated output size; if exceeded, skip animated WebP.
const maxFrames = 200
func maybeTrimFrames(frames []Frame) []Frame {
    if len(frames) > maxFrames { return frames[:maxFrames] }
    return frames
}

Prevention

When it happens

Trigger: All frames added successfully and the flush sentinel succeeded, but assembling the final container failed: OOM while allocating the output WebPData, internal inconsistency in the anim encoder state, or a libwebp version bug in the assemble path.

Common situations: Animations with many frames whose assembled output is very large, low-memory worker containers, or a libwebp build/runtime mismatch that corrupts internal encoder state.

Related errors


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