apache/cassandra · error · MarshalException

Expected 8 or 0 byte long for date (%d)

Error message

Expected 8 or 0 byte long for date (%d)

What it means

TimestampSerializer.validate accepts values that are exactly 8 bytes (a long of epoch millis) or empty (0 bytes, historically allowed for timestamps). Any other length fails this check, meaning the binary payload is not a valid timestamp encoding.

Source

Thrown at src/java/org/apache/cassandra/serializers/TimestampSerializer.java:188

                return ZonedDateTime.parse(source, fmt).toInstant().toEpochMilli();
            }
            catch (DateTimeParseException e)
            {
                continue;
            }
        }
        throw new MarshalException(String.format("Unable to parse a date/time from '%s'", source));
    }

    public static Format getJsonDateFormatter()
    {
    	return FORMATTER_TO_JSON.get();
    }

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

    public String toString(Date value)
    {
        return toStringUTC(value);
    }

    public String toStringUTC(Date value)
    {
        return value == null ? "" : FORMATTER_UTC.get().format(value.toInstant());
    }

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

    @Override

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Ensure exactly 8 bytes: ByteBuffer.allocate(8).putLong(epochMillis)
  2. Use the driver's timestamp codec with java.util.Date/Instant instead of raw buffers
  3. Verify the column type via driver metadata before binding
  4. If empty values are intentional, keep them truly 0-length, not partial writes

Example fix

// before
ByteBuffer v = ByteBuffer.allocate(4).putInt(42);
// after
ByteBuffer v = ByteBuffer.allocate(8).putLong(Instant.now().toEpochMilli());
Defensive patterns

Strategy: type-guard

Validate before calling

if (buf != null && buf.remaining() != 8 && buf.remaining() != 0) throw new IllegalArgumentException("timestamp must be 8 bytes or empty, got " + buf.remaining());

Type guard

boolean isWellFormedTimestampBytes(ByteBuffer v) { return v == null || v.remaining() == 0 || v.remaining() == 8; }

Try / catch

try {
  serializer.validate(value, byteBufferAccessor);
} catch (MarshalException e) {
  throw new DataCorruptionException("unexpected byte width for timestamp column", e);
}

Prevention

When it happens

Trigger: Binding a 4-byte int, a 16-byte value, or truncated bytes as a timestamp; deserializing a column whose bytes came from a different CQL type; hand-built payloads in custom serialization code.

Common situations: Schema mismatch after ALTER TYPE (e.g. int/date columns read as timestamp); drivers using wrong codecs; corrupted data from broken ETL that sliced buffers incorrectly.

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