gohugoio/hugo · critical

malloc failed for final webp data\n

Error message

malloc failed for final webp data\n

What it means

Printed by genwebp's encodeNRGBAAnimated (webp.c:273) when malloc fails to allocate a buffer to copy the assembled WebPData into Hugo-owned memory. The animation was encoded and assembled successfully, but the final memcpy destination cannot be allocated. The worker clears the WebPData and returns NULL, so the encoded animation is lost. This is a pure out-of-memory condition.

Source

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

        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;
}

static uint8_t initDecoderConfig(WebPDecoderConfig *config, WebPData data)
{
    if (!WebPInitDecoderConfig(config))
    {
        return 0;
    }
    if (WebPGetFeatures(data.bytes, data.size, &config->input) != VP8_STATUS_OK)
    {
        return 0;

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Raise the worker memory limit so peak (encoder buffer + copied buffer) fits.
  2. Reduce animation size to shrink the output.
  3. Serialize animated encodes so only one lives in memory at a time.
  4. Fix any upstream leak that reduces available heap before this allocation.
  5. Consider patching genwebp to hand off the WebPData bytes directly instead of malloc+memcpy (avoiding the 2x peak).

Example fix

// before (conceptual genwebp path): encode then duplicate
uint8_t *webp_data = malloc(webp_data_out.size); // fails for large outputs
memcpy(webp_data, webp_data_out.bytes, webp_data_out.size);

// after: hand off ownership of webp_data_out.bytes to the caller and skip the copy,
// OR stream the bytes out via write_blob in chunks instead of one malloc
Defensive patterns

Strategy: fallback

Validate before calling

// Reject animations whose estimated output would exceed available memory.
func canFitAssembled(available, w, h, frames int) bool {
    // crude upper bound: assume ~1 byte/pixel per frame for WebP
    est := w * h * frames
    return est*2 < available // 2x for encoder + copy
}

Prevention

When it happens

Trigger: The assembled WebP output is large enough that a same-sized malloc fails (the encoder already holds a copy, so peak memory is roughly 2x output size), or the process is under overall memory pressure from concurrent work.

Common situations: Large animated WebP output (tens of MB), workers processing multiple animations concurrently under a tight cgroup, or a memory leak in an earlier iteration that has consumed available heap.

Related errors


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