apache/cassandra · error · MarshalException

Expected 4 byte long for date (%d)

Error message

Expected 4 byte long for date (%d)

What it means

SimpleDateSerializer.validate checks that the binary value of a 'date' column is exactly 4 bytes, matching the unsigned-int day encoding. This error is thrown when deserializing/validating a value whose byte length differs, meaning the stored or transmitted bytes are not a valid date encoding.

Source

Thrown at src/java/org/apache/cassandra/serializers/SimpleDateSerializer.java:121

        {
            throw new MarshalException(String.format("Unable to make unsigned int (for date) from: '%s'", source), e);
        }
    }

    public static int timeInMillisToDay(long millis)
    {
        return (int) (Duration.ofMillis(millis).toDays() - Integer.MIN_VALUE);
    }

    public static long dayToTimeInMillis(int days)
    {
        return Duration.ofDays(days + Integer.MIN_VALUE).toMillis();
    }

    public <V> void validate(V value, ValueAccessor<V> accessor) throws MarshalException
    {
        if (accessor.size(value) != 4)
            throw new MarshalException(String.format("Expected 4 byte long for date (%d)", accessor.size(value)));
    }

    public String toString(Integer value)
    {
        if (value == null)
            return "";

        return Instant.ofEpochMilli(dayToTimeInMillis(value)).atZone(UTC).format(formatter);
    }

    public Class<Integer> getType()
    {
        return Integer.class;
    }

    @Override
    public boolean shouldQuoteCQLLiterals()
    {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Ensure exactly 4 bytes are supplied: encode via SimpleDateSerializer (timeInMillisToDay result as unsigned int)
  2. Do not pass a java.util.Date/long (8 bytes) where a date is expected; convert days encoding instead
  3. Check the column's actual type with the driver's table metadata before binding
  4. If legacy 0/empty values exist, handle empties before calling validate/deserialize

Example fix

// before
ByteBuffer v = ByteBuffer.allocate(8).putLong(System.currentTimeMillis());
// after
int days = SimpleDateSerializer.timeInMillisToDay(System.currentTimeMillis());
ByteBuffer v = TypeCodec.bigint().serialize(...); // or dateCodec.serialize("2011-02-03")
Defensive patterns

Strategy: type-guard

Validate before calling

if (buf == null || buf.remaining() != 4) throw new IllegalArgumentException("date value must be exactly 4 bytes, got " + (buf == null ? 0 : buf.remaining()));

Type guard

boolean isWellFormedDateBytes(ByteBuffer v) { return v != null && v.remaining() == 4; }

Try / catch

try {
  serializer.validate(value, byteBufferAccessor);
} catch (MarshalException e) {
  throw new DataCorruptionException("non-4-byte value in date column", e);
}

Prevention

When it happens

Trigger: Binding a 0-byte, 8-byte (long/timestamp bytes), or truncated buffer as a date value; reading a date column from a table written by a different type; passing a Java Date's 8-byte time encoding where 4-byte date encoding is required.

Common situations: Schema drift after ALTER TYPE or migration from timestamp to date; driver/client sending full timestamps into date columns; corrupted sstable data or hand-crafted byte payloads in custom code.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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