{"record":{"id":"586339b9251e68a4","repo":"henrygd/beszel","slug":"log-frame-size-d-exceeds-maximum-d","errorCode":null,"errorMessage":"log frame size (%d) exceeds maximum (%d)","messagePattern":"log frame size \\((.+?)\\) exceeds maximum \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"agent/docker.go","lineNumber":939,"sourceCode":"\tvar header [headerSize]byte\n\ttotalBytesRead := 0\n\n\tfor {\n\t\tif _, err := io.ReadFull(reader, header[:]); err != nil {\n\t\t\tif errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\n\t\tframeLen := binary.BigEndian.Uint32(header[4:])\n\t\tif frameLen == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Prevent memory exhaustion from excessively large frames\n\t\tif frameLen > maxLogFrameSize {\n\t\t\treturn fmt.Errorf(\"log frame size (%d) exceeds maximum (%d)\", frameLen, maxLogFrameSize)\n\t\t}\n\n\t\t// Check if reading this frame would exceed total log size limit\n\t\tif totalBytesRead+int(frameLen) > maxTotalLogSize {\n\t\t\t// Read and discard remaining data to avoid blocking\n\t\t\t_, _ = io.CopyN(io.Discard, reader, int64(frameLen))\n\t\t\tslog.Debug(\"Truncating logs: limit reached\", \"read\", totalBytesRead, \"limit\", maxTotalLogSize)\n\t\t\treturn nil\n\t\t}\n\n\t\tn, err := io.CopyN(builder, reader, int64(frameLen))\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\ttotalBytesRead += int(n)","sourceCodeStart":921,"sourceCodeEnd":957,"githubUrl":"https://github.com/henrygd/beszel/blob/b38fb7dafa60812cc22e6a84ce313e94f1ce0a32/agent/docker.go#L921-L957","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: blindly decoding whatever arrives\nlogs, err := getLogs(id, q)\n// after: only treat as multiplexed when content type says so (getLogs already does)\ncontentType := resp.Header.Get(\"Content-Type\")\nif !strings.HasSuffix(contentType, \"multiplexed-stream\") {\n    // decode as raw stream; avoids misread frame headers\n}","handlingStrategy":"validation","validationCode":"// only decode as multiplexed frames when the content type says so\nmultiplexed := strings.HasSuffix(resp.Header.Get(\"Content-Type\"), \"multiplexed-stream\")\nif !multiplexed { /* decode raw stream instead */ }","typeGuard":null,"tryCatchPattern":"if err := decodeDockerLogStream(reader, &builder); err != nil {\n    if strings.Contains(err.Error(), \"exceeds maximum\") {\n        log.Warn(\"corrupt log frame, truncating logs\")\n        return builder.String(), nil\n    }\n    return err\n}","preventionTips":["Connect only to genuine Docker/Podman sockets","Respect the Content-Type header before frame-parsing","Only raise maxLogFrameSize with an explicit reason"],"tags":["stream-parsing","memory-safety","docker-logs"],"backgroundTag":"frame-size-limit-exceeded","analyzedSha":"b38fb7dafa60812cc22e6a84ce313e94f1ce0a32","analyzedAt":"2026-08-31T15:10:10.149Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}