{"id":"e4020bbca048e12c","repo":"apache/kafka","slug":"string-length-length-cannot-be-negative","errorCode":null,"errorMessage":"String length ${length} cannot be negative","messagePattern":"String length (.+?) cannot be negative","errorType":"exception","errorClass":"SchemaException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/protocol/types/Type.java","lineNumber":496,"sourceCode":"                    \"The values are encoded using eight bytes in network byte order (big-endian).\";\n        }\n    };\n\n    public static final DocumentedType STRING = new DocumentedType() {\n        @Override\n        public void write(ByteBuffer buffer, Object o) {\n            byte[] bytes = Utils.utf8((String) o);\n            if (bytes.length > Short.MAX_VALUE)\n                throw new SchemaException(\"String length \" + bytes.length + \" is larger than the maximum string length.\");\n            buffer.putShort((short) bytes.length);\n            buffer.put(bytes);\n        }\n\n        @Override\n        public String read(ByteBuffer buffer) {\n            short length = buffer.getShort();\n            if (length < 0)\n                throw new SchemaException(\"String length \" + length + \" cannot be negative\");\n            return stringRead(buffer, length);\n        }\n\n        @Override\n        public int sizeOf(Object o) {\n            return 2 + Utils.utf8Length((String) o);\n        }\n\n        @Override\n        public String typeName() {\n            return \"STRING\";\n        }\n\n        @Override\n        public String validate(Object item) {\n            if (item instanceof String)\n                return (String) item;\n            else","sourceCodeStart":478,"sourceCodeEnd":514,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/protocol/types/Type.java#L478-L514","documentation":"Thrown by STRING.read() when the INT16 length prefix decoded to a negative value. The legacy STRING type stores length as a signed short, so a negative prefix indicates either a deliberately 'null-like' sentinel used by NULLABLE_STRING was misread as STRING, or the buffer is misaligned/corrupt. Raised as a SchemaException before any bytes are consumed.","triggerScenarios":"STRING.read(buffer) where buffer.getShort() returns < 0. Commonly happens when a field encoded as NULLABLE_STRING (length -1 means null) is decoded with the STRING type instead, or when the buffer position is off by one or more bytes due to an earlier mis-decoded field.","commonSituations":"Decoding a nullable string column with the wrong schema (STRING vs NULLABLE_STRING). Schema mismatch between writer and reader (e.g. API version change that introduced nullability). Buffer corruption or accidental reuse of a buffer whose position was not rewound.","solutions":["Confirm the field is encoded as STRING and not NULLABLE_STRING/COMPACT_STRING; switch the schema to the nullable variant if nulls are expected.","Verify buffer.position() is at the start of the field; rewind and re-decode the preceding fields to find misalignment.","Ensure reader and writer use the same API key and version so the field's encoding matches.","Inspect the raw bytes around the failure to rule out wire corruption."],"exampleFix":"// before: decoding a possibly-null field as STRING\nString v = Type.STRING.read(buffer); // throws on length == -1\n\n// after: use the nullable variant for fields that may be absent\nString v = Type.NULLABLE_STRING.read(buffer); // length -1 -> null","handlingStrategy":"try-catch","validationCode":"// The negative length is read internally by STRING.read() via buffer.getShort();\n// there is no public hook to pre-validate it without duplicating the read.\n// If you own the buffer you *could* peek+validate, but try/catch is the contract.\ntry {\n    String value = (String) org.apache.kafka.common.protocol.types.Type.STRING.read(buffer);\n} catch (org.apache.kafka.common.protocol.types.SchemaException e) {\n    // recover: reset buffer / skip field / close connection\n}","typeGuard":null,"tryCatchPattern":"try {\n    String value = (String) org.apache.kafka.common.protocol.types.Type.STRING.read(buffer);\n} catch (org.apache.kafka.common.protocol.types.SchemaException e) {\n    if (e.getMessage().contains(\"cannot be negative\")) {\n        // truncated or hostile frame — do not retry the same buffer\n        throw new IllegalArgumentException(\"Malformed STRING field: negative length\", e);\n    }\n    throw e;\n}","preventionTips":["Negative length on STRING.read means the signed INT16 length prefix is < 0; for nullable strings use NULLABLE_STRING (which treats -1 as null) instead of STRING.","This is a read-side corruption signal from the broker or a malformed frame — do not retry with the same payload; surface it as a protocol error.","Differentiate from BufferUnderflowException: SchemaException here means the length prefix itself is invalid, not that bytes ran out."],"tags":["protocol","serialization","schema","string","nullability"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}