henrygd/beszel · warning
log frame size (%d) exceeds maximum (%d)
Error message
log frame size (%d) exceeds maximum (%d)
What it means
decodeDockerLogStream parses the Docker multiplexed log frame format, where each frame is an 8-byte header carrying a 4-byte big-endian length. This error is returned when a single frame's declared length exceeds maxLogFrameSize, which is a memory-exhaustion guard against malicious or corrupt streams claiming gigantic frames.
Source
Thrown at agent/docker.go:939
var header [headerSize]byte
totalBytesRead := 0
for {
if _, err := io.ReadFull(reader, header[:]); err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
return nil
}
return err
}
frameLen := binary.BigEndian.Uint32(header[4:])
if frameLen == 0 {
continue
}
// Prevent memory exhaustion from excessively large frames
if frameLen > maxLogFrameSize {
return fmt.Errorf("log frame size (%d) exceeds maximum (%d)", frameLen, maxLogFrameSize)
}
// Check if reading this frame would exceed total log size limit
if totalBytesRead+int(frameLen) > maxTotalLogSize {
// Read and discard remaining data to avoid blocking
_, _ = io.CopyN(io.Discard, reader, int64(frameLen))
slog.Debug("Truncating logs: limit reached", "read", totalBytesRead, "limit", maxTotalLogSize)
return nil
}
n, err := io.CopyN(builder, reader, int64(frameLen))
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
return nil
}
return err
}
totalBytesRead += int(n)View on GitHub (pinned to b38fb7dafa)
Solutions
- Verify the stream Content-Type to correctly detect multiplexed vs raw streams before decoding
- Check that the endpoint is a genuine Docker/Podman socket, not an intermediary rewriting bytes
- If legitimately huge log lines are expected, raise maxLogFrameSize deliberately
- Retry the log fetch; a single corrupt frame is usually transient
Example fix
// before: blindly decoding whatever arrives
logs, err := getLogs(id, q)
// after: only treat as multiplexed when content type says so (getLogs already does)
contentType := resp.Header.Get("Content-Type")
if !strings.HasSuffix(contentType, "multiplexed-stream") {
// decode as raw stream; avoids misread frame headers
} Defensive patterns
Strategy: validation
Validate before calling
// only decode as multiplexed frames when the content type says so
multiplexed := strings.HasSuffix(resp.Header.Get("Content-Type"), "multiplexed-stream")
if !multiplexed { /* decode raw stream instead */ } Try / catch
if err := decodeDockerLogStream(reader, &builder); err != nil {
if strings.Contains(err.Error(), "exceeds maximum") {
log.Warn("corrupt log frame, truncating logs")
return builder.String(), nil
}
return err
} Prevention
- Connect only to genuine Docker/Podman sockets
- Respect the Content-Type header before frame-parsing
- Only raise maxLogFrameSize with an explicit reason
When it happens
Trigger: A log frame header declares a length larger than maxLogFrameSize — a corrupt/malformed stream, a non-multiplexed raw stream misinterpreted as frames, or a hostile daemon/socket feeding oversized length fields.
Common situations: A raw (non-multiplexed) TTY stream whose text bytes are misread as a frame header with an enormous length; middleboxes/proxies mangling the stream; connecting to something that is not a real Docker socket on the configured endpoint.
Related errors
AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31).
Data as JSON: /api/errors/586339b9251e68a4.
Report an issue: GitHub.