{"record":{"id":"e0fcf950a1cd167d","repo":"apache/cassandra","slug":"not-enough-bytes-to-read-dth-component","errorCode":null,"errorMessage":"Not enough bytes to read %dth component","messagePattern":"Not enough bytes to read (.+?)th component","errorType":"validation","errorClass":"MarshalException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/CQL3Type.java","lineNumber":511,"sourceCode":"                if (buffer.remaining() < 4)\n                    throw new MarshalException(String.format(\"Not enough bytes to read size of %dth component\", i));\n\n                int size = buffer.getInt();\n\n                if (first)\n                    first = false;\n                else\n                    target.append(\", \");\n\n                // size < 0 means null value\n                if (size < 0)\n                {\n                    target.append(\"null\");\n                    continue;\n                }\n\n                if (buffer.remaining() < size)\n                    throw new MarshalException(String.format(\"Not enough bytes to read %dth component\", i));\n\n                ByteBuffer field = ByteBufferUtil.readBytes(buffer, size);\n                target.append(type.type(i).asCQL3Type().toCQLLiteral(field));\n            }\n            target.append(')');\n            return target.toString();\n        }\n\n        @Override\n        public final boolean equals(Object o)\n        {\n            if(!(o instanceof Tuple))\n                return false;\n\n            Tuple that = (Tuple)o;\n            return type.equals(that.type);\n        }\n","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/CQL3Type.java#L493-L529","documentation":"After reading a tuple component's declared size, the buffer must contain that many bytes for the component's value. If it ends early the serialized tuple is truncated and MarshalException is thrown naming the component index.","triggerScenarios":"A component size prefix (e.g. 8) followed by fewer than 8 bytes; hand-built tuple buffers with wrong sizes; corrupted stored tuple blobs.","commonSituations":"Off-by-N errors when manually concatenating component bytes; transport truncation; attempting to render partially read data.","solutions":["Ensure each component's serialized bytes fully follow its size prefix","Serialize tuples via TupleType APIs rather than manual ByteBuffer composition","Catch MarshalException around literal rendering of untrusted blobs"],"exampleFix":"// before\nByteBuffer b = ByteBuffer.allocate(4); b.putInt(8); // 8 declared, 0 present\nString lit = tupleType.asCQL3Type().toCQLLiteral(b);\n// after\nByteBuffer b = tupleType.serializer().serialize(tupleValue);\nString lit = tupleType.asCQL3Type().toCQLLiteral(b);","handlingStrategy":"try-catch","validationCode":"ByteBuffer dup = buffer.duplicate();\nwhile (dup.hasRemaining()) { int size = dup.getInt(); if (dup.remaining() < size) throw new MarshalException(\"component truncated\"); dup.position(dup.position() + size); }","typeGuard":null,"tryCatchPattern":"try { String lit = tupleType.asCQL3Type().toCQLLiteral(buffer); } catch (MarshalException e) { handleCorruptTuple(e); }","preventionTips":["Keep size prefixes consistent with actual component byte counts","Round-trip test custom serialization against the official serializer","Wrap rendering of untrusted blobs in MarshalException handling"],"tags":["cassandra","cql","serialization","tuple","bytebuffer"],"backgroundTag":"unexpected-response-shape","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"}