apache/cassandra · error · MarshalException
Expected 0 or at least 4 bytes (%d)
Error message
Expected 0 or at least 4 bytes (%d)
What it means
DecimalSerializer serializes a BigDecimal as a 4-byte scale followed by an unscaled integer. A non-empty decimal value must therefore be at least 4 bytes; anything in between cannot even hold the scale field, so validate() rejects it with this formatted MarshalException including the actual byte size.
Source
Thrown at src/java/org/apache/cassandra/serializers/DecimalSerializer.java:62
if (value == null)
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
BigInteger bi = value.unscaledValue();
int scale = value.scale();
byte[] bibytes = bi.toByteArray();
ByteBuffer bytes = ByteBuffer.allocate(4 + bibytes.length);
bytes.putInt(scale);
bytes.put(bibytes);
bytes.rewind();
return bytes;
}
public <T> void validate(T value, ValueAccessor<T> accessor) throws MarshalException
{
// We at least store the scale.
if (!accessor.isEmpty(value) && accessor.size(value) < 4)
throw new MarshalException(String.format("Expected 0 or at least 4 bytes (%d)", accessor.size(value)));
}
public String toString(BigDecimal value)
{
return value == null ? "" : value.toString();
}
public Class<BigDecimal> getType()
{
return BigDecimal.class;
}
}
View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Write decimal values via DecimalSerializer.serialize(BigDecimal) so the 4-byte scale is always present
- Check the column type matches the stored bytes (schema mismatch)
- If data is truncated on disk, restore from backup or repair
- Pad manual buffers to include the scale (4 bytes) plus unscaled value
Example fix
// before
ByteBuffer bad = ByteBufferUtil.bytes(new byte[]{1, 2}); // 2 bytes, no scale
// after
ByteBuffer ok = DecimalSerializer.instance.serialize(new BigDecimal("1.23")); // scale + unscaled Defensive patterns
Strategy: validation
Validate before calling
public static void checkDecimal(ByteBuffer buf) {
if (buf != null && buf.hasRemaining() && buf.remaining() < 4)
throw new MarshalException("decimal value too short: " + buf.remaining());
} Type guard
public static boolean isValidDecimalBytes(ByteBuffer buf) {
return buf == null || !buf.hasRemaining() || buf.remaining() >= 4;
} Try / catch
try {
decimalType.validate(value);
} catch (MarshalException e) {
logger.warn("Invalid decimal bytes: {}", e.getMessage());
} Prevention
- Always serialize via DecimalSerializer.serialize(BigDecimal)
- Check column type matches data when reusing raw bytes
- Guard against partial writes with checksums
When it happens
Trigger: validate/deserialize called on a non-empty buffer of 1-3 bytes — e.g. a decimal column cell truncated, bytes of a different type stored in a decimal column, or a manual buffer written without the 4-byte scale.
Common situations: Schema drift (column type changed but old bytes remain); hand-crafted test data missing the scale integer; corruption from partial writes.
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 8 or 0 byte value for a double (%d)
- Expected at least 3 bytes for a duration (%d)
- Not enough bytes to read size of %dth field %s
- Not enough bytes to read %dth field %s
- Not enough bytes to read size of %dth component
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/64637c83a8246137.
Report an issue: GitHub.