apache/cassandra · error · MarshalException

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

Error message

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

What it means

MarshalException raised by DurationSerializer.validate after decoding the three VInt components of a duration: the days component exceeds the 32-bit int range that the duration type guarantees (enforced by canBeCastToInt). The value being read was not written by a valid duration encoder or is corrupt.

Source

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

        }
    }

    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);
        }
    }

    /**
     * Checks that the specified {@code long} can be cast to an {@code int} without information lost.
     *

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Construct durations with Duration.newInstance ensuring days fits an int
  2. Re-serialize via DurationSerializer rather than manual vint packing
  3. Verify integrity of stored bytes if corruption is suspected
  4. Validate user-provided durations before serializing

Example fix

// before
long days = 1L << 40; byte[] packed = packVInt(days); // out of int range
// after
Duration d = Duration.newInstance(0, (int) 30, 0);
ByteBuffer ok = DurationSerializer.instance.serialize(d);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

public static boolean isSafeDayCount(long days) {
    return daysFitsInt(days);
}

Try / catch

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

Prevention

When it happens

Trigger: validate/deserialize of a duration whose days vint decodes to a value outside int range — corrupted bytes or hand-encoded vints with oversized day counts.

Common situations: Storage corruption; custom serialization writing days as a long vint beyond int bounds; malformed user input converted without range checks.

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/44ed9ca9fa9a7572. Report an issue: GitHub.