apache/cassandra · error · MarshalException

The duration months must be a 32 bits integer but was: %d

Error message

The duration months must be a 32 bits integer but was: %d

What it means

After decoding the vints, validate() checks the months field fits in a signed 32-bit int. Vints can carry larger values, so an out-of-int-range months component cannot be represented as Duration's int fields and is rejected with this MarshalException.

Source

Thrown at src/java/org/apache/cassandra/serializers/DurationSerializer.java:92

        {
            // this should never happen with a DataInputBuffer
            throw new AssertionError("Unexpected error", e);
        }
    }

    public <V> void validate(V value, ValueAccessor<V> accessor) throws MarshalException
    {
        if (accessor.size(value) < 3)
            throw new MarshalException(String.format("Expected at least 3 bytes for a duration (%d)", accessor.size(value)));

        try (DataInputBuffer in = new DataInputBuffer(accessor.toBuffer(value), true))  // FIXME: value input buffer
        {
            long monthsAsLong = in.readVInt();
            long daysAsLong = in.readVInt();
            long nanoseconds = in.readVInt();

            if (!canBeCastToInt(monthsAsLong))
                throw new MarshalException(String.format("The duration months must be a 32 bits integer but was: %d",
                                                         monthsAsLong));
            if (!canBeCastToInt(daysAsLong))
                throw new MarshalException(String.format("The duration days must be a 32 bits integer but was: %d",
                                                         daysAsLong));
            int months = (int) monthsAsLong;
            int days = (int) daysAsLong;

            if (!((months >= 0 && days >= 0 && nanoseconds >= 0) || (months <= 0 && days <=0 && nanoseconds <=0)))
                throw new MarshalException(String.format("The duration months, days and nanoseconds must be all of the same sign (%d, %d, %d)",
                                                         months, days, nanoseconds));
        }
        catch (IOException e)
        {
            // this should never happen with a DataInputBuffer
            throw new AssertionError("Unexpected error", e);
        }
    }

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Ensure durations are constructed via Duration.newInstance(int months, int days, long nanos) which enforces int months
  2. Re-serialize with the official serializer instead of hand-packed vints
  3. Check data integrity if value came from storage
  4. If input comes from user strings, validate ranges before conversion

Example fix

// before
byte[] packed = packVInt(Long.valueOf(Integer.MAX_VALUE) + 1); // months out of int range
// after
Duration d = Duration.newInstance(12, 0, 0); // months fits int
ByteBuffer ok = DurationSerializer.instance.serialize(d);
Defensive patterns

Strategy: validation

Validate before calling

public static boolean monthsFitsInt(long months) {
    return months >= Integer.MIN_VALUE && months <= Integer.MAX_VALUE;
}

Type guard

public static boolean isEncodableDuration(long months, long days, long nanos) {
    return monthsFitsInt(months) && days >= Integer.MIN_VALUE && days <= Integer.MAX_VALUE;
}

Try / catch

try {
    serializer.validate(buffer, accessor);
} catch (MarshalException e) {
    if (e.getMessage().contains("months must be a 32 bits")) logger.error("months overflow");
}

Prevention

When it happens

Trigger: validate/deserialize of a duration whose encoded months vint exceeds Integer.MAX_VALUE or is below Integer.MIN_VALUE — typically hand-crafted or corrupted bytes, since normal Duration construction uses ints.

Common situations: Corrupted SSTable bytes decoded as huge vints; manually packing vints with values beyond int range; fuzz/malformed input on user-supplied duration strings via native protocol.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/0093566c58fda1a0. Report an issue: GitHub.