apache/kafka · error · InvalidRecordException
Invalid negative header key size {}
Error message
Invalid negative header key size {} What it means
Thrown on the InputStream partial-read path when the varint decoded for an individual header's key length is negative. Header keys are UTF-8 strings whose length is encoded as a non-negative varint; a negative value means the byte sequence is corrupt and the parser refuses to skip a negative number of bytes.
Source
Thrown at clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecord.java:408
DefaultRecordBatch.incrementSequence(baseSequence, offsetDelta) :
RecordBatch.NO_SEQUENCE;
// skip key
int keySize = ByteUtils.readVarint(input);
skipBytes(input, keySize);
// skip value
int valueSize = ByteUtils.readVarint(input);
skipBytes(input, valueSize);
// skip header
int numHeaders = ByteUtils.readVarint(input);
if (numHeaders < 0)
throw new InvalidRecordException("Found invalid number of record headers " + numHeaders);
for (int i = 0; i < numHeaders; i++) {
int headerKeySize = ByteUtils.readVarint(input);
if (headerKeySize < 0)
throw new InvalidRecordException("Invalid negative header key size " + headerKeySize);
skipBytes(input, headerKeySize);
// headerValueSize
int headerValueSize = ByteUtils.readVarint(input);
skipBytes(input, headerValueSize);
}
return new PartialDefaultRecord(sizeInBytes, attributes, offset, timestamp, sequence, keySize, valueSize);
} catch (BufferUnderflowException | IllegalArgumentException e) {
throw new InvalidRecordException("Found invalid record structure", e);
}
}
/**
* Skips over and discards exactly {@code bytesToSkip} bytes from the input stream.
*
* We require a loop over {@link InputStream#skip(long)} because it is possible for InputStream to skip smallerView on GitHub (pinned to c31c9215e1)
Solutions
- Dump the failing batch with kafka-dump-log --print-data-log and locate the record whose header section is malformed.
- Audit the producer's header construction; ensure every header has a non-null key (DefaultRecord.writeTo rejects null keys at line 207) and uses the standard Header/RecordHeader type.
- Validate the batch CRC; if it fails, treat the record as corrupt on disk and recover from a replica.
- Round-trip the same header set through DefaultRecord.writeTo in a producer-side test to confirm the encoding matches what the consumer expects.
Defensive patterns
Strategy: try-catch
Validate before calling
// headerKeySize is a varint decoded inside the parser. If you decode it
// yourself when walking headers:
int headerKeySize = ByteUtils.readVarint(input);
if (headerKeySize < 0) { /* malformed header key length */ } Type guard
private static boolean isValidHeaderKeySize(int headerKeySize) {
return headerKeySize >= 0;
} Try / catch
try {
PartialDefaultRecord r = DefaultRecord.readPartiallyFrom(input, baseOffset, baseTimestamp, baseSequence, logAppendTime);
} catch (InvalidRecordException | IOException e) {
LOG.warn("Negative header key size near offset {}", baseOffset, e);
} Prevention
- When building headers via RecordHeader/AbstractHeaders, key lengths are always non-negative; never hand-craft header bytes.
- Validate header keys are non-empty UTF-8 strings on the producer side to catch serialization bugs.
- Isolate header parsing failures so one bad header skips only its record, not the entire batch.
When it happens
Trigger: Raised at DefaultRecord.java:407-408 inside the header-skipping loop of readPartiallyFrom when ByteUtils.readVarint(input) at line 406 returns a value < 0. Triggered by a malformed header section in a record being stream-scanned, typically because the bytes that should encode headerKeySize decode as -1 or another negative varint.
Common situations: Producer that wrote headers with a custom or buggy serializer (e.g. emitting a null-marker varint where a key-length was expected), on-disk corruption of the header region of a record, or a third-party client that encodes header key lengths differently from the Apache Kafka spec.
Related errors
- Found invalid number of record headers {}
- Found invalid number of record headers. {} is larger than th
- Invalid record size: expected {} bytes in record payload, bu
- Invalid record size: expected to read {} bytes in record pay
- Found invalid record structure
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/9c0bbd237c336178.json.
Report an issue: GitHub.