apache/cassandra · error · MarshalException
Expected at least 3 bytes for a duration (%d)
Error message
Expected at least 3 bytes for a duration (%d)
What it means
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.
Source
Thrown at src/java/org/apache/cassandra/serializers/DurationSerializer.java:83
try (DataInputBuffer in = new DataInputBuffer(accessor.toBuffer(value), true)) // TODO: make a value input buffer
{
int months = in.readVInt32();
int days = in.readVInt32();
long nanoseconds = in.readVInt();
return Duration.newInstance(months, days, nanoseconds);
}
catch (IOException e)
{
// 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)",View on GitHub (pinned to 88fd0f6a0e)
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
Example fix
// before
ByteBuffer bad = ByteBufferUtil.bytes(new byte[]{1, 2}); // too short
// after
ByteBuffer ok = DurationSerializer.instance.serialize(Duration.newInstance(1, 2, 3)); Defensive patterns
Strategy: validation
Validate before calling
public static void checkDuration(ByteBuffer buf) {
if (buf != null && buf.remaining() > 0 && buf.remaining() < 3)
throw new MarshalException("duration too short: " + buf.remaining());
} Type guard
public static boolean isPlausibleDurationBytes(ByteBuffer buf) {
return buf == null || !buf.hasRemaining() || buf.remaining() >= 3;
} Try / catch
try {
Duration d = DurationSerializer.instance.deserialize(buffer);
} catch (MarshalException e) {
logger.warn("Invalid duration bytes: {}", e.getMessage());
} Prevention
- Build durations only via Duration.newInstance or Duration.from
- Never hand-pack vint buffers
- Keep duration column types stable across schema changes
When it happens
Trigger: 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.
Common situations: Application writing an int/short into a duration column; partially written data; schema drift where the column previously held another type.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Expected 0 or at least 4 bytes (%d)
- Expected 8 or 0 byte value for a double (%d)
- The duration months must be a 32 bits integer but was: %d
- The duration days must be a 32 bits integer but was: %d
- The duration months, days and nanoseconds must be all of the
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/52c4521e803332a1.
Report an issue: GitHub.