{"id":"9c0bbd237c336178","repo":"apache/kafka","slug":"invalid-negative-header-key-size","errorCode":null,"errorMessage":"Invalid negative header key size {}","messagePattern":"Invalid negative header key size (.+?)","errorType":"exception","errorClass":"InvalidRecordException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecord.java","lineNumber":408,"sourceCode":"                DefaultRecordBatch.incrementSequence(baseSequence, offsetDelta) :\n                RecordBatch.NO_SEQUENCE;\n\n            // skip key\n            int keySize = ByteUtils.readVarint(input);\n            skipBytes(input, keySize);\n\n            // skip value\n            int valueSize = ByteUtils.readVarint(input);\n            skipBytes(input, valueSize);\n\n            // skip header\n            int numHeaders = ByteUtils.readVarint(input);\n            if (numHeaders < 0)\n                throw new InvalidRecordException(\"Found invalid number of record headers \" + numHeaders);\n            for (int i = 0; i < numHeaders; i++) {\n                int headerKeySize = ByteUtils.readVarint(input);\n                if (headerKeySize < 0)\n                    throw new InvalidRecordException(\"Invalid negative header key size \" + headerKeySize);\n                skipBytes(input, headerKeySize);\n\n                // headerValueSize\n                int headerValueSize = ByteUtils.readVarint(input);\n                skipBytes(input, headerValueSize);\n            }\n\n            return new PartialDefaultRecord(sizeInBytes, attributes, offset, timestamp, sequence, keySize, valueSize);\n        } catch (BufferUnderflowException | IllegalArgumentException e) {\n            throw new InvalidRecordException(\"Found invalid record structure\", e);\n        }\n    }\n\n\n    /**\n     * Skips over and discards exactly {@code bytesToSkip} bytes from the input stream.\n     *\n     * We require a loop over {@link InputStream#skip(long)} because it is possible for InputStream to skip smaller","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/record/internal/DefaultRecord.java#L390-L426","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// headerKeySize is a varint decoded inside the parser. If you decode it\n// yourself when walking headers:\nint headerKeySize = ByteUtils.readVarint(input);\nif (headerKeySize < 0) { /* malformed header key length */ }","typeGuard":"private static boolean isValidHeaderKeySize(int headerKeySize) {\n    return headerKeySize >= 0;\n}","tryCatchPattern":"try {\n    PartialDefaultRecord r = DefaultRecord.readPartiallyFrom(input, baseOffset, baseTimestamp, baseSequence, logAppendTime);\n} catch (InvalidRecordException | IOException e) {\n    LOG.warn(\"Negative header key size near offset {}\", baseOffset, e);\n}","preventionTips":["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."],"tags":["kafka","record-format","deserialization","headers","invalid-record"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}