apache/kafka · error · InvalidRecordException

Found invalid number of record headers. {} is larger than th

Error message

Found invalid number of record headers. {} is larger than the remaining size of the buffer

What it means

Thrown on the ByteBuffer path when numHeaders is non-negative but greater than buffer.remaining(). Since each header needs at least one byte, the count cannot fit in the remaining payload; the library treats this as structural corruption rather than trying to read past the buffer limit.

Source

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

            int offsetDelta = ByteUtils.readVarint(buffer);
            long offset = baseOffset + offsetDelta;
            int sequence = baseSequence >= 0 ?
                    DefaultRecordBatch.incrementSequence(baseSequence, offsetDelta) :
                    RecordBatch.NO_SEQUENCE;

            // read key
            int keySize = ByteUtils.readVarint(buffer);
            ByteBuffer key = Utils.readBytes(buffer, keySize);

            // 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);
        }
    }

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Confirm the producer is on a supported client version and uses the standard record builder; capture a single failing record with kafka-console-consumer --max-messages 1 and hex-inspect the header section.
  2. Check the broker log for CRC validation failures on the same partition/offset to distinguish in-flight corruption from on-disk corruption.
  3. If only one partition is affected, stop the affected producer, validate its header construction, and re-publish the bad batch.
  4. Recover the segment from an in-sync replica if disk corruption is confirmed by kafka-dump-log.
Defensive patterns

Strategy: validation

Validate before calling

// After you decode numHeaders, before letting the parser continue:
if (numHeaders > buffer.remaining()) {
    // declared header count cannot fit; record is corrupt or truncated
    throw new InvalidRecordException("declared headers exceed remaining buffer");
}

Type guard

// Bounds-check the header count against the remaining payload.
private static boolean headersFitInBuffer(int numHeaders, ByteBuffer buffer) {
    return numHeaders >= 0 && numHeaders <= buffer.remaining();
}

Try / catch

try {
    DefaultRecord r = DefaultRecord.readFrom(buffer, baseOffset, baseTimestamp, baseSequence, logAppendTime);
} catch (InvalidRecordException e) {
    LOG.warn("Header count exceeds remaining bytes near offset {}", baseOffset, e);
}

Prevention

When it happens

Trigger: Raised at DefaultRecord.java:341-342 when ByteUtils.readVarint returns a header count larger than buffer.remaining() after the key/value sections have already been consumed. Common when the headers count field was overwritten with a large value or when the key/value length prefixes were misread, leaving too few bytes for the claimed header array.

Common situations: Producer client producing records where key/value lengths disagree with the actual bytes (off-by-one in a custom partitioner/serializer), corruption of the batch in the page cache or on disk, or a consumer pointed at a topic that another vendor's broker wrote in a subtly different record format.

Related errors


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