gohugoio/hugo · error
[%d] Error reading blob data (size: %llu read: %zu) \n
Error message
[%d] Error reading blob data (size: %llu read: %zu) \n
What it means
Printed by genwebp's handle_commands (webp.c:593) when the blob header's declared size does not match the bytes fread returned. Logs blob_id, declared size, and actual read count. Identical semantics to the genavif counterpart (823): the canonical stream-desync signal for genwebp.
Source
Thrown at internal/warpc/genwebp/webp.c:593
blob_size = *(uint32_t *)&blob_header[12];
blob_data = malloc((size_t)blob_size);
if (blob_data == NULL)
{
// Out of memory. Drain the blob from the input stream so the next
// command stays aligned, then report the error to the client instead
// of leaving the stream corrupted with no response.
drain_bytes(stream, (size_t)blob_size);
OutputMessage err_output = {0};
err_output.header = input.header;
snprintf(err_output.header.err, sizeof(err_output.header.err),
"out of memory allocating %u bytes for blob data", blob_size);
write_output_message(&err_output);
goto cleanup;
}
read_bytes = fread(blob_data, 1, (size_t)blob_size, stream);
if (read_bytes != (size_t)blob_size)
{
fprintf(stderr, "[%d] Error reading blob data (size: %llu read: %zu) \n", blob_id, (unsigned long long)blob_size, read_bytes);
goto cleanup;
}
OutputMessage output = {0};
output.header = input.header;
if (strcmp(input.header.command, "decode") == 0)
{
WebPData data;
data.bytes = blob_data;
data.size = (size_t)blob_size;
WebPDecoderConfig config;
if (!initDecoderConfig(&config, data))
{
strncpy(output.header.err, "Failed to initialize WebPDecoderConfig", sizeof(output.header.err) - 1);
write_output_message(&output);View on GitHub (pinned to 52c9bd7908)
Solutions
- Compute size from the actual byte length of the payload about to be written: size := uint32(len(pix)).
- For animated encodes, size = stride*height*frameCount, with stride = width*4 for RGBA.
- Treat any partial write (n != len) from the Go writer as fatal.
- On Go-side errors mid-send, close and respawn the worker rather than reusing a half-drained pipe.
- Log the declared size at send time and correlate with the size printed here.
Example fix
// before: size hardcoded / cached, mismatches actual payload size := uint32(1024 * 1024) // stale binary.LittleEndian.PutUint32(hdr[12:], size) // after pix := flattenRGBA(frames, w, h, frameCount) size := uint32(len(pix)) binary.LittleEndian.PutUint32(hdr[12:], size) w.Write(hdr); w.Write(pix)
Defensive patterns
Strategy: validation
Validate before calling
func webpBlobHeader(id uint32, payload []byte) []byte {
h := make([]byte, 16)
copy(h[0:8], []byte("TAK35EM1"))
binary.LittleEndian.PutUint32(h[8:12], id)
binary.LittleEndian.PutUint32(h[12:16], uint32(len(payload)))
return h
} Prevention
- Derive size from len(payload), not from a cached field.
- For RGBA: payload length = width*4*height (or *frameCount for animated).
- Treat any partial write as fatal and respawn the worker.
- Log declared size at send time to correlate with the worker's stderr print.
When it happens
Trigger: Header size field disagrees with the bytes the host wrote (wrong stride*width*height, wrong bytes-per-pixel for has_alpha, endianness packing error), host closed the pipe partway through the blob, or a previous over-read advanced the stream past the true blob start.
Common situations: RGB vs RGBA byte-count mismatch (3 vs 4 bytes/pixel), animated frame count differing from declared, partial write from a flushed buffered writer, stale cached size after the source image changed, or test fixtures with a hardcoded size field.
Related errors
- [%d] Error reading blob data (size: %llu read: %zu) \n
- Error reading blob header\n
- Error reading blob header\n
- Error parsing JSON line\n
- Error: Line did not parse to a valid JSON object\n
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/8fb36d4912e24af7.
Report an issue: GitHub.