{"record":{"id":"cc23f5cd797d0ab6","repo":"apache/cassandra","slug":"unexpected-extraneous-bytes-after-getcollectionn","errorCode":null,"errorMessage":"Unexpected extraneous bytes after + getCollectionName() + value","messagePattern":"Unexpected extraneous bytes after \\+ getCollectionName\\(\\) \\+ value","errorType":"validation","errorClass":"MarshalException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/serializers/CollectionSerializer.java","lineNumber":98,"sourceCode":"                throw new MarshalException(\"The data cannot be deserialized as a \" + getCollectionName());\n\n            // If the received bytes are not corresponding to a collection, the size might be a huge number.\n            // In such a case we do not want to initialize the list with that size as it can result\n            // in an OOM. On the other hand we do not want to have to resize the list\n            // if we can avoid it, so we put a reasonable limit on the initialCapacity.\n            List<V> values = new ArrayList<>(Math.min(elements, 256));\n            int offset = sizeOfCollectionSize();\n\n            for (int i = 0; i < elements; i++)\n            {\n                V value = readValue(input, accessor, offset);\n                offset += sizeOfValue(value, accessor);\n\n                values.add(value);\n            }\n\n            if (!accessor.isEmptyFromOffset(input, offset))\n                throw new MarshalException(\"Unexpected extraneous bytes after \" + getCollectionName() + \" value\");\n\n            return values;\n        }\n        catch (BufferUnderflowException | IndexOutOfBoundsException e)\n        {\n            throw new MarshalException(\"Not enough bytes to read a \" + getCollectionName());\n        }\n    }\n\n    /**\n     * Return the collection name for error messages.\n     * @return the collection name for error messages.\n     */\n    private String getCollectionName()\n    {\n        return toLowerCaseLocalized(getType().getSimpleName());\n    }\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/serializers/CollectionSerializer.java#L80-L116","documentation":"CollectionSerializer.unpack() deserializes a serialized collection (list/set/map) by reading count-prefixed elements. After reading all elements declared by the count, it verifies no leftover bytes remain in the input; if they do, the buffer is not a valid encoding of this collection type, so MarshalException is thrown.","triggerScenarios":"Calling deserialize/validate (via unpack) on a byte buffer whose byte length exceeds the sum of the element count prefix plus all encoded elements — e.g. corrupted SSTable/mutation bytes, manually crafted byte buffers, or bytes written by an incompatible serializer version.","commonSituations":"Hand-building collection ByteBuffers for tests or UDFs with trailing garbage; upgrading across Cassandra versions where collection encoding changed; corruption from wrong serialization of nested collections.","solutions":["Verify the byte buffer is produced by CollectionSerializer.serialize and not concatenated with unrelated bytes","Check for trailing bytes by confirming buffer length matches the encoded collection size","Re-serialize the value with the current Cassandra version's serializer instead of reusing old bytes","If reading from storage, run repair/scrub to detect corruption"],"exampleFix":"// before\nByteBuffer bad = ByteBuffer.allocate(serialized.remaining() + extra.length);\nbad.put(serialized); bad.put(extra); // trailing bytes\n// after\nByteBuffer good = CollectionSerializer.getInstance(...).serialize(value);","handlingStrategy":"validation","validationCode":"public static void checkCollectionBytes(ByteBuffer buf) {\n    if (buf == null || buf.remaining() == 0) return;\n    ByteBuffer dup = buf.duplicate();\n    int count = dup.getInt();\n    long total = 4;\n    for (int i = 0; i < count; i++) {\n        int size = dup.getInt(); total += 4;\n        if (size >= 0) { total += size; dup.position(dup.position() + size); }\n    }\n    if (dup.hasRemaining()) throw new MarshalException(\"trailing bytes in collection value\");\n}","typeGuard":"public static boolean isValidCollection(ByteBuffer buf) {\n    try { checkCollectionBytes(buf); return true; } catch (Exception e) { return false; }\n}","tryCatchPattern":"try {\n    List<ByteBuffer> values = serializer.deserialize(buffer);\n} catch (MarshalException e) {\n    logger.warn(\"Malformed collection value: {}\", e.getMessage());\n    // treat as absent value\n}","preventionTips":["Always produce collection bytes via CollectionSerializer.serialize","Never append unrelated bytes to a serialized collection buffer","Validate buffers in tests before shipping serialization changes"],"tags":["serialization","cassandra","bytebuffer","collections"],"backgroundTag":"invalid-argument-format","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}