{"record":{"id":"52c4521e803332a1","repo":"apache/cassandra","slug":"expected-at-least-3-bytes-for-a-duration-d","errorCode":null,"errorMessage":"Expected at least 3 bytes for a duration (%d)","messagePattern":"Expected at least 3 bytes for a duration \\((.+?)\\)","errorType":"validation","errorClass":"MarshalException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/serializers/DurationSerializer.java","lineNumber":83,"sourceCode":"\n        try (DataInputBuffer in = new DataInputBuffer(accessor.toBuffer(value), true))  // TODO: make a value input buffer\n        {\n            int months = in.readVInt32();\n            int days = in.readVInt32();\n            long nanoseconds = in.readVInt();\n            return Duration.newInstance(months, days, nanoseconds);\n        }\n        catch (IOException e)\n        {\n            // this should never happen with a DataInputBuffer\n            throw new AssertionError(\"Unexpected error\", e);\n        }\n    }\n\n    public <V> void validate(V value, ValueAccessor<V> accessor) throws MarshalException\n    {\n        if (accessor.size(value) < 3)\n            throw new MarshalException(String.format(\"Expected at least 3 bytes for a duration (%d)\", accessor.size(value)));\n\n        try (DataInputBuffer in = new DataInputBuffer(accessor.toBuffer(value), true))  // FIXME: value input buffer\n        {\n            long monthsAsLong = in.readVInt();\n            long daysAsLong = in.readVInt();\n            long nanoseconds = in.readVInt();\n\n            if (!canBeCastToInt(monthsAsLong))\n                throw new MarshalException(String.format(\"The duration months must be a 32 bits integer but was: %d\",\n                                                         monthsAsLong));\n            if (!canBeCastToInt(daysAsLong))\n                throw new MarshalException(String.format(\"The duration days must be a 32 bits integer but was: %d\",\n                                                         daysAsLong));\n            int months = (int) monthsAsLong;\n            int days = (int) daysAsLong;\n\n            if (!((months >= 0 && days >= 0 && nanoseconds >= 0) || (months <= 0 && days <=0 && nanoseconds <=0)))\n                throw new MarshalException(String.format(\"The duration months, days and nanoseconds must be all of the same sign (%d, %d, %d)\",","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/serializers/DurationSerializer.java#L65-L101","documentation":"A duration is encoded as three vints (months, days, nanoseconds); even minimal encodings occupy at least 3 bytes. validate() rejects values smaller than 3 bytes before attempting to decode, reporting the actual size.","triggerScenarios":"validate/deserialize on a buffer of 0-2 bytes for a duration column — truncated cell, empty-but-non-null value, or wrong-typed bytes stored in a duration column.","commonSituations":"Application writing an int/short into a duration column; partially written data; schema drift where the column previously held another type.","solutions":["Use DurationSerializer.serialize(Duration) to build the value","Check column type vs stored bytes for schema mismatch","Restore/repair truncated data from disk","Never write hand-packed buffers; always pass a Duration instance"],"exampleFix":"// before\nByteBuffer bad = ByteBufferUtil.bytes(new byte[]{1, 2}); // too short\n// after\nByteBuffer ok = DurationSerializer.instance.serialize(Duration.newInstance(1, 2, 3));","handlingStrategy":"validation","validationCode":"public static void checkDuration(ByteBuffer buf) {\n    if (buf != null && buf.remaining() > 0 && buf.remaining() < 3)\n        throw new MarshalException(\"duration too short: \" + buf.remaining());\n}","typeGuard":"public static boolean isPlausibleDurationBytes(ByteBuffer buf) {\n    return buf == null || !buf.hasRemaining() || buf.remaining() >= 3;\n}","tryCatchPattern":"try {\n    Duration d = DurationSerializer.instance.deserialize(buffer);\n} catch (MarshalException e) {\n    logger.warn(\"Invalid duration bytes: {}\", e.getMessage());\n}","preventionTips":["Build durations only via Duration.newInstance or Duration.from","Never hand-pack vint buffers","Keep duration column types stable across schema changes"],"tags":["serialization","cassandra","duration","validate"],"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"}