{"id":"d27fbc6dc79d329a","repo":"apache/kafka","slug":"field-size-size-cannot-be-negative","errorCode":null,"errorMessage":"field size ${size} cannot be negative","messagePattern":"field size (.+?) cannot be negative","errorType":"exception","errorClass":"SchemaException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/protocol/types/TaggedFields.java","lineNumber":97,"sourceCode":"    }\n\n    @Override\n    public NavigableMap<Integer, Object> read(ByteBuffer buffer) {\n        int numTaggedFields = ByteUtils.readUnsignedVarint(buffer);\n        if (numTaggedFields == 0) {\n            return Collections.emptyNavigableMap();\n        }\n        NavigableMap<Integer, Object> objects = new TreeMap<>();\n        int prevTag = -1;\n        for (int i = 0; i < numTaggedFields; i++) {\n            int tag = ByteUtils.readUnsignedVarint(buffer);\n            if (tag <= prevTag) {\n                throw new RuntimeException(\"Invalid or out-of-order tag \" + tag);\n            }\n            prevTag = tag;\n            int size = ByteUtils.readUnsignedVarint(buffer);\n            if (size < 0)\n                throw new SchemaException(\"field size \" + size + \" cannot be negative\");\n            if (size > buffer.remaining())\n                throw new SchemaException(\"Error reading field of size \" + size + \", only \" + buffer.remaining() + \" bytes available\");\n\n            Field field = fields.get(tag);\n            if (field == null) {\n                byte[] bytes = new byte[size];\n                buffer.get(bytes);\n                objects.put(tag, new RawTaggedField(tag, bytes));\n            } else {\n                objects.put(tag, field.type.read(buffer));\n            }\n        }\n        return objects;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public int sizeOf(Object o) {","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/protocol/types/TaggedFields.java#L79-L115","documentation":"Thrown by TaggedFields.read when the per-field size varint decodes to a negative int. Although the size is read as an unsigned varint, an overlong/malformed varint can overflow into the sign bit and produce a negative int; the guard refuses it before sizing a byte[] allocation. It indicates corrupt bytes at the size position of a tagged field.","triggerScenarios":"TaggedFields.read calls ByteUtils.readUnsignedVarint(buffer) for the size; the resulting int is checked `size < 0`. Hit when the bytes at that position do not form a valid unsigned varint (e.g. a 6-byte overlong encoding, garbage from a misaligned buffer, or a frame whose tag was consumed incorrectly leaving non-varint bytes).","commonSituations":"Buffer position misalignment after reading the wrong number of parent-struct fields; a truncated/garbled flexible-version payload; man-in-the-middle or on-disk corruption; reading a non-tagged payload with a schema that expects tagged fields (or vice versa).","solutions":["Confirm the buffer position is at the tagged-fields section - i.e. all preceding struct fields for this API version were consumed.","Verify the API version matches: tagged fields only exist in flexible (v3+) messages; do not attempt to read TaggedFields for non-flexible versions.","Hex-dump the bytes around the position to confirm a well-formed unsigned varint; reject the frame if it is malformed.","If reproducing from a recorded payload, re-record with current client and schema versions."],"exampleFix":"// before - assuming every version has tagged fields\nNavigableMap<Integer, Object> tags = taggedFields.read(buf);\n\n// after - only read tagged fields for flexible versions\nif (apiVersion >= apiVersions.flexibleVersion(apiKey)) {\n    tags = taggedFields.read(buf);\n} else {\n    tags = Collections.emptyNavigableMap();\n}","handlingStrategy":"try-catch","validationCode":"// The size is a varint decoded inside TaggedFields.read; a negative result\n// implies a malformed varint the caller cannot pre-see. Only a minimum\n// buffer check is feasible before the call.\nif (buffer == null || buffer.remaining() < 1) {\n    throw new IllegalArgumentException(\"buffer too small for tagged-field size varint\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    NavigableMap<Integer, Object> tf = taggedFields.read(buffer);\n} catch (org.apache.kafka.common.protocol.types.SchemaException e) {\n    if (e.getMessage().contains(\"field size\") && e.getMessage().contains(\"cannot be negative\")) {\n        // malformed varint -> corrupt wire data\n        throw new CorruptFrameException(e);\n    }\n    throw e;\n}","preventionTips":["Unsigned-varint decoders can return negative ints on malformed input; treat any negative size as frame corruption.","Do not retry the same bytes; close the channel and reconnect.","Validate total frame length at the framing layer so a truncated varint is caught earlier.","Log the decoded size value to distinguish corruption from a genuine oversized field."],"tags":["protocol","serialization","tagged-fields","flexible-versions","buffer-corruption"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}