apache/kafka · critical · InvalidRecordException
Invalid value size found for control record key. Must have a
Error message
Invalid value size found for control record key. Must have at least {} bytes, but found only {} What it means
ControlRecordType.parseTypeId(ByteBuffer) (line 90) requires at least 4 bytes (2-byte version + 2-byte type) per the fixed control-record key schema. A key shorter than 4 bytes cannot be interpreted and is rejected as InvalidRecordException, indicating the record batch is malformed, truncated, or corrupt.
Source
Thrown at clients/src/main/java/org/apache/kafka/common/record/internal/ControlRecordType.java:90
return type;
}
public ByteBuffer recordKey() {
if (this == UNKNOWN)
throw new IllegalArgumentException("Cannot serialize UNKNOWN control record type");
return buffer.duplicate();
}
public int controlRecordKeySize() {
return buffer.remaining();
}
public static short parseTypeId(ByteBuffer key) {
// We should duplicate the original buffer since it will be read again in some cases, for example,
// read by KafkaRaftClient and RaftClient.Listener
ByteBuffer buffer = key.duplicate();
if (buffer.remaining() < CONTROL_RECORD_KEY_SIZE)
throw new InvalidRecordException("Invalid value size found for control record key. " +
"Must have at least " + CONTROL_RECORD_KEY_SIZE + " bytes, but found only " + buffer.remaining());
short version = buffer.getShort();
if (version < ControlRecordTypeSchema.LOWEST_SUPPORTED_VERSION)
throw new InvalidRecordException("Invalid version found for control record: " + version +
". May indicate data corruption");
if (version > ControlRecordTypeSchema.HIGHEST_SUPPORTED_VERSION) {
log.debug("Received unknown control record key version {}. Parsing as version {}", version,
ControlRecordTypeSchema.HIGHEST_SUPPORTED_VERSION);
version = ControlRecordTypeSchema.HIGHEST_SUPPORTED_VERSION;
}
ControlRecordTypeSchema schema = new ControlRecordTypeSchema(new ByteBufferAccessor(buffer), version);
return schema.type();
}
public static ControlRecordType fromTypeId(short typeId) {
switch (typeId) {View on GitHub (pinned to c31c9215e1)
Solutions
- Inspect the source segment with kafka-dump-log to confirm the malformed key.
- Verify the writing broker is a compatible Kafka version and shut down cleanly.
- Truncate or replace the corrupt segment / restore the KRaft snapshot from a healthy replica.
Defensive patterns
Strategy: validation
Validate before calling
// Validate buffer length before parsing the control record key (requires >= 4 bytes)
import java.nio.ByteBuffer;
import org.apache.kafka.common.record.ControlRecordType;
private static final int CONTROL_RECORD_KEY_SIZE = 4; // version(short) + type(short)
ByteBuffer dup = key.duplicate();
if (dup.remaining() >= CONTROL_RECORD_KEY_SIZE) {
short typeId = ControlRecordType.parseTypeId(dup);
} else {
// key is too short / corrupted; handle as bad data
} Type guard
import java.nio.ByteBuffer;
static boolean hasControlRecordKeySize(ByteBuffer key) {
return key != null && key.remaining() >= 4;
}
// usage: if (hasControlRecordKeySize(key)) { ControlRecordType.parseTypeId(key); } Try / catch
try {
short typeId = ControlRecordType.parseTypeId(key);
} catch (org.apache.kafka.common.InvalidRecordException e) {
// key buffer is undersized; treat as corrupt/truncated control record
} Prevention
- The control record key is a fixed 4-byte structure: 2-byte version + 2-byte type.
- Always duplicate() the source buffer before length checks so you do not advance the caller's position.
- Treat an undersized key as data corruption: quarantine the batch rather than retrying blindly.
- When forwarding keys from an upstream source, enforce a minimum size at your trust boundary.
When it happens
Trigger: Calling ControlRecordType.parse(key) or parseTypeId(key) on a control record whose key ByteBuffer has fewer than 4 bytes remaining; reached during consumer/replica/KRaft reads of transaction, commit, leader-change, snapshot, or voter control batches.
Common situations: Corrupted or truncated log segment on disk; partial write from a crashed broker; follower out of sync producing a short batch; manual tampering or a bad custom serializer.
Related errors
- Invalid version found for control record: {}. May indicate d
- Expected %s control record type(%d), but found %s
- Invalid record size: expected {} bytes in record payload, bu
- Unknown topology description status id: {id}
- Unknown acknowledge type id: {id}
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/129b14086617c6fa.json.
Report an issue: GitHub.