{"record":{"id":"71f31c6275e5f635","repo":"apache/cassandra","slug":"invalid-empty-vector-value","errorCode":null,"errorMessage":"Invalid empty vector value","messagePattern":"Invalid empty vector value","errorType":"validation","errorClass":"MarshalException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/db/marshal/VectorType.java","lineNumber":386,"sourceCode":"        // This code base always works with a list that is RandomAccess, so can use .get to avoid allocation\n        for (int i = 0; i < dimension; i++)\n        {\n            Object value = values.get(i);\n            if (value == null || (value instanceof ByteBuffer && elementSerializer.isNull((ByteBuffer) value)))\n                throw new MarshalException(String.format(\"Element at index %d is null (expected type %s); given %s\", i, elementType.asCQL3Type(), values));\n        }\n    }\n\n    private <V> void checkConsumedFully(V buffer, ValueAccessor<V> accessor, int offset)\n    {\n        int remaining = accessor.sizeFromOffset(buffer, offset);\n        if (remaining > 0)\n            throw new MarshalException(\"Unexpected \" + remaining + \" extraneous bytes after \" + asCQL3Type() + \" value\");\n    }\n    \n    private static void rejectNullOrEmptyValue()\n    {\n        throw new MarshalException(\"Invalid empty vector value\");\n    }\n\n    @Override\n    public ByteBuffer getMaskedValue()\n    {\n        List<ByteBuffer> values = Collections.nCopies(dimension, elementType.getMaskedValue());\n        return serializer.pack(values, ByteBufferAccessor.instance);\n    }\n\n    public abstract class VectorSerializer extends TypeSerializer<List<T>>\n    {\n        public abstract <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR);\n\n        public abstract <V> List<V> unpack(V buffer, ValueAccessor<V> accessor);\n        public abstract <V> V pack(List<V> elements, ValueAccessor<V> accessor);\n\n        @Override\n        public String toString(List<T> value)","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/marshal/VectorType.java#L368-L404","documentation":"VectorType rejects empty or null vector values because a vector's size is fixed by its dimension; an empty byte buffer cannot represent dimension elements. rejectNullOrEmptyValue is invoked from decomposeAsFloat and fromComparableBytes when the incoming value is null or has zero remaining bytes.","triggerScenarios":"Calling decomposeAsFloat or fromComparableBytes with a null buffer or an empty (0-byte) ByteBuffer for a vector column; inserting an empty blob into a vector column path that goes through these methods.","commonSituations":"Application code sending an empty payload for a vector column; deserialization returning empty bytes; migration tooling producing empty values; test code constructing vectors incorrectly.","solutions":["Ensure the value contains exactly dimension * elementSize bytes before calling decomposeAsFloat/fromComparableBytes","Treat null/empty as a special case in application code and skip the call or insert a null vector explicitly if allowed","Fix producer code (driver, migration script) so it never emits empty vectors for non-zero dimension columns"],"exampleFix":"// before\nfloat[] floats = vectorType.decomposeAsFloat(ByteBuffer.wrap(new byte[0]));\n// after\nif (value == null || value.remaining() == 0) throw new IllegalArgumentException(\"vector value must not be empty\");\nfloat[] floats = vectorType.decomposeAsFloat(value);","handlingStrategy":"validation","validationCode":"if (value == null || value.remaining() == 0) throw new IllegalArgumentException(\"vector value must be non-empty\");","typeGuard":null,"tryCatchPattern":"try { float[] v = vectorType.decomposeAsFloat(buf); } catch (MarshalException e) { log.warn(\"empty/invalid vector: {}\", e.getMessage()); v = null; }","preventionTips":["Never insert empty blobs into vector columns; use null instead if allowed","Check producer/driver code never emits zero-length payloads","Add size assertions in ingestion pipelines"],"tags":["cassandra","serialization","vector-type","empty-value"],"backgroundTag":"empty-required-field","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}