apache/kafka · error · InvalidRecordException

Invalid record size: expected to read {} bytes in record pay

Error message

Invalid record size: expected to read {} bytes in record payload, but instead read {}

What it means

Thrown after the record is fully parsed when the bytes consumed from recordStart to current position do not equal the declared body size. It is a self-consistency check on the magic-v2 record framing: every field read correctly but the total length disagrees with the size prefix, so the structure is corrupt.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecord.java:352

            // read value
            int valueSize = ByteUtils.readVarint(buffer);
            ByteBuffer value = Utils.readBytes(buffer, valueSize);

            int numHeaders = ByteUtils.readVarint(buffer);
            if (numHeaders < 0)
                throw new InvalidRecordException("Found invalid number of record headers " + numHeaders);
            if (numHeaders > buffer.remaining())
                throw new InvalidRecordException("Found invalid number of record headers. " + numHeaders + " is larger than the remaining size of the buffer");

            final Header[] headers;
            if (numHeaders == 0)
                headers = Record.EMPTY_HEADERS;
            else
                headers = readHeaders(buffer, numHeaders);

            // validate whether we have read all header bytes in the current record
            if (buffer.position() - recordStart != sizeOfBodyInBytes)
                throw new InvalidRecordException("Invalid record size: expected to read " + sizeOfBodyInBytes +
                        " bytes in record payload, but instead read " + (buffer.position() - recordStart));

            int totalSizeInBytes = ByteUtils.sizeOfVarint(sizeOfBodyInBytes) + sizeOfBodyInBytes;
            return new DefaultRecord(totalSizeInBytes, attributes, offset, timestamp, sequence, key, value, headers);
        } catch (BufferUnderflowException | IllegalArgumentException e) {
            throw new InvalidRecordException("Found invalid record structure", e);
        }
    }

    public static PartialDefaultRecord readPartiallyFrom(InputStream input,
                                                         long baseOffset,
                                                         long baseTimestamp,
                                                         int baseSequence,
                                                         Long logAppendTime) throws IOException {
        int sizeOfBodyInBytes = ByteUtils.readVarint(input);
        int totalSizeInBytes = ByteUtils.sizeOfVarint(sizeOfBodyInBytes) + sizeOfBodyInBytes;

        return readPartiallyFrom(input, totalSizeInBytes, baseOffset, baseTimestamp,

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Identify the producing client for the failing partition/offset and confirm it goes through the Apache Kafka producer path; remove any interceptors that mutate record bytes.
  2. Round-trip the suspected record through DefaultRecord.writeTo / readFrom in a unit test to find which field's length prefix disagrees with its payload.
  3. Validate the batch CRC with kafka-dump-log; if CRC fails the data is corrupt on disk or in transit, otherwise the producer itself emitted a malformed frame.
  4. Recover the affected log segment from a healthy replica or skip the corrupt record with the consumer's isolation/auto-reset policy if data loss is acceptable.
Defensive patterns

Strategy: try-catch

Validate before calling

// You would have to re-walk attributes+timestampDelta+offsetDelta+key+value+
// headers to predict total bytes. Not practical; rely on the parser's own
// recordStart/position() check and catch the exception.

Try / catch

try {
    DefaultRecord r = DefaultRecord.readFrom(buffer, baseOffset, baseTimestamp, baseSequence, logAppendTime);
} catch (InvalidRecordException e) {
    // bytes consumed != sizeOfBodyInBytes declared in the varint length prefix
    LOG.warn("Record length mismatch near offset {}", baseOffset, e);
}

Prevention

When it happens

Trigger: Raised at DefaultRecord.java:351-353 inside readFrom(ByteBuffer, ...) when (buffer.position() - recordStart) != sizeOfBodyInBytes after key, value, and headers were all read. Happens when one of the varint length fields (keySize, valueSize, numHeaders, headerKeySize, headerValueSize) was decoded successfully but consumed a number of bytes that does not sum to the declared body length.

Common situations: Custom interceptor or Converter that rewrites a record body without updating the outer size varint, a serialization library that mis-encodes a varint, version skew between a broker using one record-batch framing and a client expecting another, or partial on-disk corruption that left individual fields readable but the total length wrong.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/9681b52e0148b34f.json. Report an issue: GitHub.