{"record":{"id":"da91b43fc1b01d3f","repo":"apache/cassandra","slug":"not-enough-bytes-to-read-the-end-of-component-byte","errorCode":null,"errorMessage":"Not enough bytes to read the end-of-component byte of component","messagePattern":"Not enough bytes to read the end-of-component byte of component","errorType":"validation","errorClass":"MarshalException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java","lineNumber":325,"sourceCode":"        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;\n        }\n    }\n\n    @Override\n    public void checkConstraints(ByteBuffer input, ColumnConstraints constraints) throws ConstraintViolationException\n    {\n        // no constraints defined for the partition keys\n        if (!constraints.hasRelevantConstraints())\n            return;\n\n        ValueAccessor<ByteBuffer> accessor = ByteBufferAccessor.instance;\n","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java#L307-L343","documentation":"Each composite component must end with a single end-of-component byte (normally 0), which also determines ascending/descending order. AbstractCompositeType.validate() throws MarshalException 'Not enough bytes to read the end-of-component byte of component <i>' when the buffer is exhausted right after a component's value bytes, with no room for this terminator.","triggerScenarios":"Validating a composite blob that ends exactly after a component's value without the trailing 0x00 end-of-component byte — e.g. manually built keys omitting the terminator or truncated payloads.","commonSituations":"Hand-written composite encoders forgetting the 0 terminator; byte-range slicing dropping the last byte; older/other-system formats (e.g. Thrift-era helpers) that differ in encoding; corrupted sstable values.","solutions":["Append the required 0x00 end-of-component byte after every component value when building composites manually","Use CompositeType.decompose()/build to produce correct framing automatically","Check any slicing/copy code so it does not trim the final byte","Verify totals: every component consumes comparator + 2 + len + 1 bytes","Run nodetool scrub if corrupt stored data is the source"],"exampleFix":"// before\nout.put(value); // component written without end-of-component byte\n// after\nout.put(value);\nout.put((byte) 0x00);","handlingStrategy":"validation","validationCode":"// ensure at least 1 byte remains after each component value\nint off = 0, i = 0;\nwhile (off < buf.remaining()) {\n    int hdr = /* comparator size */ 1;\n    int len = ((buf.get(off + hdr) & 0xff) << 8) | (buf.get(off + hdr + 1) & 0xff);\n    if (buf.remaining() < off + hdr + 2 + len + 1)\n        throw new IllegalArgumentException(\"Component \" + i + \" missing end-of-component byte\");\n    off += hdr + 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 the end-of-component\"))\n        logger.error(\"Composite missing 0x00 terminator — use decompose() to build values\");\n    else throw e;\n}","preventionTips":["Always write the 0x00 end-of-component byte after each component when encoding manually","Prefer CompositeType.decompose over bespoke encoders","Beware byte-slicing that trims the final terminator byte","Scrub tables (nodetool scrub) when stored values are suspect"],"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"}