{"id":"129b14086617c6fa","repo":"apache/kafka","slug":"invalid-value-size-found-for-control-record-key-m","errorCode":null,"errorMessage":"Invalid value size found for control record key. Must have at least {} bytes, but found only {}","messagePattern":"Invalid value size found for control record key\\. Must have at least (.+?) bytes, but found only (.+?)","errorType":"exception","errorClass":"InvalidRecordException","httpStatus":null,"severity":"critical","filePath":"clients/src/main/java/org/apache/kafka/common/record/internal/ControlRecordType.java","lineNumber":90,"sourceCode":"        return type;\n    }\n\n    public ByteBuffer recordKey() {\n        if (this == UNKNOWN)\n            throw new IllegalArgumentException(\"Cannot serialize UNKNOWN control record type\");\n        return buffer.duplicate();\n    }\n\n    public int controlRecordKeySize() {\n        return buffer.remaining();\n    }\n\n    public static short parseTypeId(ByteBuffer key) {\n        // We should duplicate the original buffer since it will be read again in some cases, for example,\n        // read by KafkaRaftClient and RaftClient.Listener\n        ByteBuffer buffer = key.duplicate();\n        if (buffer.remaining() < CONTROL_RECORD_KEY_SIZE)\n            throw new InvalidRecordException(\"Invalid value size found for control record key. \" +\n                    \"Must have at least \" + CONTROL_RECORD_KEY_SIZE + \" bytes, but found only \" + buffer.remaining());\n\n        short version = buffer.getShort();\n        if (version < ControlRecordTypeSchema.LOWEST_SUPPORTED_VERSION)\n            throw new InvalidRecordException(\"Invalid version found for control record: \" + version +\n                    \". May indicate data corruption\");\n\n        if (version > ControlRecordTypeSchema.HIGHEST_SUPPORTED_VERSION) {\n            log.debug(\"Received unknown control record key version {}. Parsing as version {}\", version,\n                    ControlRecordTypeSchema.HIGHEST_SUPPORTED_VERSION);\n            version = ControlRecordTypeSchema.HIGHEST_SUPPORTED_VERSION;\n        }\n        ControlRecordTypeSchema schema = new ControlRecordTypeSchema(new ByteBufferAccessor(buffer), version);\n        return schema.type();\n    }\n\n    public static ControlRecordType fromTypeId(short typeId) {\n        switch (typeId) {","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/record/internal/ControlRecordType.java#L72-L108","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate buffer length before parsing the control record key (requires >= 4 bytes)\nimport java.nio.ByteBuffer;\nimport org.apache.kafka.common.record.ControlRecordType;\n\nprivate static final int CONTROL_RECORD_KEY_SIZE = 4; // version(short) + type(short)\n\nByteBuffer dup = key.duplicate();\nif (dup.remaining() >= CONTROL_RECORD_KEY_SIZE) {\n    short typeId = ControlRecordType.parseTypeId(dup);\n} else {\n    // key is too short / corrupted; handle as bad data\n}","typeGuard":"import java.nio.ByteBuffer;\n\nstatic boolean hasControlRecordKeySize(ByteBuffer key) {\n    return key != null && key.remaining() >= 4;\n}\n\n// usage: if (hasControlRecordKeySize(key)) { ControlRecordType.parseTypeId(key); }","tryCatchPattern":"try {\n    short typeId = ControlRecordType.parseTypeId(key);\n} catch (org.apache.kafka.common.InvalidRecordException e) {\n    // key buffer is undersized; treat as corrupt/truncated control record\n}","preventionTips":["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."],"tags":["control-record","data-corruption","deserialization"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}