{"record":{"id":"22fee33de8dad484","repo":"grpc/grpc-go","slug":"received-the-frame-length-d-larger-than-the-limit","errorCode":null,"errorMessage":"received the frame length %d larger than the limit %d","messagePattern":"received the frame length (.+?) larger than the limit (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/alts/internal/conn/common.go","lineNumber":62,"sourceCode":"\t} else {\n\t\thead = make([]byte, total)\n\t\tcopy(head, in)\n\t}\n\ttail = head[len(in):]\n\treturn head, tail\n}\n\n// ParseFramedMsg parse the provided buffer and returns a frame of the format\n// msgLength+msg and any remaining bytes in that buffer.\nfunc ParseFramedMsg(b []byte, maxLen uint32) ([]byte, []byte, error) {\n\t// If the size field is not complete, return the provided buffer as\n\t// remaining buffer.\n\tlength, sufficientBytes := parseMessageLength(b)\n\tif !sufficientBytes {\n\t\treturn nil, b, nil\n\t}\n\tif length > maxLen {\n\t\treturn nil, nil, fmt.Errorf(\"received the frame length %d larger than the limit %d\", length, maxLen)\n\t}\n\tif len(b) < int(length)+4 { // account for the first 4 msg length bytes.\n\t\t// Frame is not complete yet.\n\t\treturn nil, b, nil\n\t}\n\treturn b[:MsgLenFieldSize+length], b[MsgLenFieldSize+length:], nil\n}\n\n// parseMessageLength returns the message length based on frame header. It also\n// returns a boolean indicating if the buffer contains sufficient bytes to parse\n// the length header. If there are insufficient bytes, (0, false) is returned.\nfunc parseMessageLength(b []byte) (uint32, bool) {\n\tif len(b) < MsgLenFieldSize {\n\t\treturn 0, false\n\t}\n\tmsgLenField := b[:MsgLenFieldSize]\n\treturn binary.LittleEndian.Uint32(msgLenField), true\n}","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/credentials/alts/internal/conn/common.go#L44-L80","documentation":"ParseFramedMsg (common.go:54-62) reads the 4-byte little-endian frame length header from an ALTS record and rejects frames whose declared length exceeds maxLen. On the record path maxLen is altsRecordLengthLimit (1 MiB). This guards against memory-exhaustion / oversized-record attacks on the ALTS secure channel.","triggerScenarios":"The ALTS peer (or a man-in-the-middle / corrupted stream) sends a record whose length header claims > 1 MiB. The read loop in record.go calls ParseFramedMsg on each chunk and surfaces this.","commonSituations":"A buggy or malicious peer; stream corruption after a TLS/ALTS failure; an interop test sending an oversized frame; a protocol implementation mismatch producing giant records.","solutions":["Ensure the peer uses a compatible, uncorrupted ALTS record implementation.","If this is a test, lower the amount of data per record to stay under 1 MiB.","Treat this as a connection-fatal error: close and re-establish the ALTS connection."],"exampleFix":"// before: test sends a frame of 2 MiB\n// after: keep ALTS records <= 1 MiB (altsRecordLengthLimit)\nframe := makeFrame(payload[:1<<20])","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, _, err := conn.ParseFramedMsg(buf, altsRecordLengthLimit); err != nil {\n    // oversized/malformed ALTS record: tear down the connection\n    log.Printf(\"closing ALTS conn: %v\", err)\n    altsConn.Close()\n}","preventionTips":["Treat oversized-frame errors as fatal and reconnect.","Ensure peers emit ALTS records <= 1 MiB.","Fuzz-test your ALTS endpoint with oversized frames to confirm it rejects them."],"tags":["go","grpc","alts","framing","security"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}