apache/cassandra · error · MarshalException

The duration months, days and nanoseconds must be all of the

Error message

The duration months, days and nanoseconds must be all of the same sign (%d, %d, %d)

What it means

Cassandra durations must have months, days and nanoseconds all non-negative or all non-positive; mixed-sign components are rejected. validate() enforces this after decoding and reports the three parsed values in the message.

Source

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

            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.
     *
     * @param l the {@code long} to check
     * @return {@code true} if the specified {@code long} can be cast to an {@code int} without information lost,
     * {@code false} otherwise.
     */
    private boolean canBeCastToInt(long l)
    {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Normalize the duration so all components share the same sign before serializing
  2. Clamp or reject negative components at the application boundary
  3. If data came from storage, fix offending rows via scrub/migration
  4. Use Duration.from(String) which enforces sign constraints from text input

Example fix

// before
Duration bad = Duration.newInstance(1, -2, 0); // mixed signs
// after
Duration ok = Duration.newInstance(-1, -2, 0); // all negative, allowed
Defensive patterns

Strategy: validation

Validate before calling

public static boolean sameSign(long a, long b, long c) {
    boolean nonNeg = a >= 0 && b >= 0 && c >= 0;
    boolean nonPos = a <= 0 && b <= 0 && c <= 0;
    return nonNeg || nonPos;
}
// guard: if (!sameSign(months, days, nanos)) reject before serializing

Type guard

public static boolean isValidDuration(Duration d) {
    return sameSign(d.getMonths(), d.getDays(), d.getNanoseconds());
}

Try / catch

try {
    Duration d = DurationSerializer.instance.deserialize(buffer);
} catch (MarshalException e) {
    if (e.getMessage().contains("same sign")) logger.warn("mixed-sign duration rejected");
}

Prevention

When it happens

Trigger: validate/deserialize of a duration whose decoded components have differing signs — e.g. Duration.newInstance(1, -2, 0), negative nanoseconds with positive months, or corrupted bytes decoding to mixed signs.

Common situations: User input like 'P1MT-2D' style strings parsed to mixed-sign values; application computing negative day offsets; driver/UDF passing arbitrary ints.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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