{"id":"76f5f34613250de9","repo":"apache/kafka","slug":"error-reading-string-of-length-length-only-r","errorCode":null,"errorMessage":"Error reading string of length ${length}, only ${remaining} bytes available","messagePattern":"Error reading string of length (.+?), only (.+?) bytes available","errorType":"exception","errorClass":"SchemaException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/protocol/types/Type.java","lineNumber":124,"sourceCode":"\n        /**\n         * Documentation of the Type.\n         *\n         * @return details about valid values, representation\n         */\n        public abstract String documentation();\n\n        @Override\n        public String toString() {\n            return typeName();\n        }\n    }\n\n    public static String stringRead(ByteBuffer buffer, int length) {\n        if (length > Short.MAX_VALUE)\n            throw new SchemaException(\"String length \" + length + \" is larger than the maximum string length.\");\n        if (length > buffer.remaining())\n            throw new SchemaException(\"Error reading string of length \" + length + \", only \" + buffer.remaining() + \" bytes available\");\n        String result = Utils.utf8(buffer, length);\n        buffer.position(buffer.position() + length);\n        return result;\n    }\n\n    public static ByteBuffer bytesRead(ByteBuffer buffer, int size) {\n        if (size > buffer.remaining())\n            throw new SchemaException(\"Error reading bytes of size \" + size + \", only \" + buffer.remaining() + \" bytes available\");\n\n        int limit = buffer.limit();\n        int newPosition = buffer.position() + size;\n        buffer.limit(newPosition);\n        ByteBuffer val = buffer.slice();\n        buffer.limit(limit);\n        buffer.position(newPosition);\n        return val;\n    }\n","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/protocol/types/Type.java#L106-L142","documentation":"Thrown by stringRead() when the STRING field's declared length is positive and within the INT16 limit, but fewer bytes remain in the ByteBuffer than the length claims. This is the canonical truncated-frame / short-read guard for the legacy STRING type and is raised as a SchemaException before any UTF-8 decode is attempted.","triggerScenarios":"STRING.read(buffer) (or stringRead via COMPACT_STRING.read) where buffer.remaining() < length after the length prefix was consumed. Reached during ApiMessage/Struct deserialization when the source buffer was sliced too short, the network read returned a partial frame, or a preceding field's length was wrong so the position is off.","commonSituations":"Non-blocking socket returned an incomplete response that was passed to the decoder anyway. A buffer was rewound/sliced incorrectly between fields. Client and broker disagree on the message schema (e.g. custom plugin or older client). Frame corruption on the wire from a proxy or load balancer.","solutions":["Ensure the full Kafka response frame is accumulated before deserialization (NetworkReceive / size-prefixed framing must complete).","Inspect buffer.position(), limit(), and remaining() at the failure site; log the declared length vs remaining to confirm truncation.","Verify no intermediary (proxy, TLS terminator, custom interceptor) is truncating or rewriting the payload.","Match client version to broker version for the failing API key to rule out a schema drift."],"exampleFix":"// before: decoding a possibly-incomplete frame\nString v = Type.stringRead(buffer, length); // throws when remaining < length\n\n// after: only decode once the full frame is buffered\nif (buffer.remaining() < length) {\n    // accumulate more bytes from the socket / re-read before decoding\n    return null;\n}\nString v = Utils.utf8(buffer, length);","handlingStrategy":"validation","validationCode":"// Both length and buffer.remaining() are known before the call.\nif (length > buffer.remaining()) {\n    throw new IllegalArgumentException(\n        \"Need \" + length + \" bytes but only \" + buffer.remaining() + \" available\");\n}\nString value = org.apache.kafka.common.protocol.types.Type.stringRead(buffer, length);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always compare the declared length against buffer.remaining() before handing the buffer to stringRead/bytesRead — a truncated frame is the most common cause.","Ensure your framing layer reads complete frames before deserializing; partial reads happen when a socket read boundary is mistaken for a message boundary.","If the buffer is external/untrusted, prefer try/catch SchemaException around the read as a backstop."],"tags":["protocol","serialization","schema","truncation","bytebuffer"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}