{"record":{"id":"50a23a4716b2b719","repo":"apache/cassandra","slug":"not-enough-bytes-to-read-value-size-of-component","errorCode":null,"errorMessage":"Not enough bytes to read value size of component ","messagePattern":"Not enough bytes to read value size of component ","errorType":"validation","errorClass":"MarshalException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java","lineNumber":313,"sourceCode":"    {\n        validate(bb, ByteBufferAccessor.instance);\n    }\n\n    @Override\n    public <V> void validate(V input, ValueAccessor<V> accessor)\n    {\n        boolean isStatic = readIsStatic(input, accessor);\n        int offset = startingOffset(isStatic);\n\n        int i = 0;\n        V previous = null;\n        while (!accessor.isEmptyFromOffset(input, offset))\n        {\n            AbstractType<?> comparator = validateComparator(i, input, accessor, offset);\n            offset += getComparatorSize(i, input, accessor, offset);\n\n            if (accessor.sizeFromOffset(input, offset) < 2)\n                throw new MarshalException(\"Not enough bytes to read value size of component \" + i);\n            int length = accessor.getUnsignedShort(input, offset);\n            offset += 2;\n\n            if (accessor.sizeFromOffset(input, offset) < length)\n                throw new MarshalException(\"Not enough bytes to read value of component \" + i);\n            V value = accessor.slice(input, offset, length);\n            offset += length;\n\n            comparator.validateCollectionMember(value, previous, accessor);\n\n            if (accessor.isEmptyFromOffset(input, offset))\n                throw new MarshalException(\"Not enough bytes to read the end-of-component byte of component\" + i);\n            byte b = accessor.getByte(input, offset++);\n            if (b != 0 && !accessor.isEmptyFromOffset(input, offset))\n                throw new MarshalException(\"Invalid bytes remaining after an end-of-component at component\" + i);\n\n            previous = value;\n            ++i;","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java#L295-L331","documentation":"AbstractCompositeType.validate() walks the serialized composite value: for each component it reads a 2-byte unsigned-short size, then that many value bytes, then an end-of-component byte. If fewer than 2 bytes remain where the component's value size should be, MarshalException 'Not enough bytes to read value size of component <i>' is thrown, indicating a truncated or malformed composite blob.","triggerScenarios":"Validating (or deserializing via CQL/client insert) a composite-typed value whose bytes end immediately after a comparator header, before the 2-byte length field of component i can be read.","commonSituations":"Client code hand-constructing composite keys/blobs with truncated payloads; corrupted values from a bad driver or migration tool; binary blobs pasted between systems with wrong encoding; reading partial rows from corrupted sstables.","solutions":["Inspect the client code that builds the composite value and ensure each component is serialized as comparator + 2-byte length + value + 0 end-byte","Use the driver's/type's own serializer (CompositeType.build/buildAlias) instead of manual byte assembly","Validate the input length before sending: each component needs at least comparator-size + 3 bytes","If data came from a migration, re-export with correct tooling and compare byte lengths","If from a corrupted sstable, run nodetool scrub on the table"],"exampleFix":"// before: manual truncating copy\nbyte[] out = Arrays.copyOfRange(src, 0, src.length - 1); // drops end byte\n// after\nByteBuffer out = CompositeType.getInstance(Arrays.asList(UTF8Type.instance, Int32Type.instance))\n                              .decompose(Arrays.asList(\"a\", 1));","handlingStrategy":"validation","validationCode":"// client-side pre-check for a composite blob\nint off = 0, i = 0;\nwhile (off < buf.remaining()) {\n    int compHeader = /* comparator size for this composite type, min 1 */ 1;\n    if (buf.remaining() - off < compHeader + 2)\n        throw new IllegalArgumentException(\"Truncated composite at component \" + i);\n    int len = ((buf.get(off + compHeader) & 0xff) << 8) | (buf.get(off + compHeader + 1) & 0xff);\n    if (buf.remaining() - off - compHeader - 2 < len + 1)\n        throw new IllegalArgumentException(\"Component \" + i + \" overruns buffer\");\n    off += compHeader + 2 + len + 1; ++i;\n}","typeGuard":null,"tryCatchPattern":"try {\n    type.validate(bytes);\n} catch (MarshalException e) {\n    if (e.getMessage().startsWith(\"Not enough bytes to read value size\"))\n        logger.error(\"Truncated composite blob — rebuild with CompositeType.decompose\");\n    else throw e;\n}","preventionTips":["Never assemble composite bytes manually; use the type's decompose/build API","Don't round-trip binary composite values through String/UTF-8","Base64-encode composite blobs for logs/transport and decode before sending","Validate blobs with type.validate(bytes) in tests for any migration tooling"],"tags":["serialization","composite-type","validation"],"backgroundTag":"schema-validation-failed","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"}