apache/cassandra · error · InvalidTypeException
Invalid decimal value, expecting at least 4 bytes but got
Error message
Invalid decimal value, expecting at least 4 bytes but got
What it means
CQL decimal wire format is a 4-byte big-endian scale (varint exponent) followed by the unscaled BigInteger bytes. deserialize() requires at least 4 bytes to read the scale; fewer means the payload cannot be a decimal and the codec throws InvalidTypeException.
Source
Thrown at src/java/org/apache/cassandra/cql3/functions/types/TypeCodec.java:1342
{
if (value == null) return null;
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;
}
@Override
public BigDecimal deserialize(ByteBuffer bytes, ProtocolVersion protocolVersion)
{
if (bytes == null || bytes.remaining() == 0) return null;
if (bytes.remaining() < 4)
throw new InvalidTypeException(
"Invalid decimal value, expecting at least 4 bytes but got " + bytes.remaining());
bytes = bytes.duplicate();
int scale = bytes.getInt();
byte[] bibytes = new byte[bytes.remaining()];
bytes.get(bibytes);
BigInteger bi = new BigInteger(bibytes);
return new BigDecimal(bi, scale);
}
}
/**
* This codec maps a CQL {@link DataType#cdouble()} to a Java {@link Double}.
*/
private static class DoubleCodec extends PrimitiveDoubleCodec
{
View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Encode decimals properly: scale int followed by unscaled BigInteger.toByteArray() (see TypeCodec decimal serialize).
- Match the codec to the column's actual type (double codec for 8-byte doubles, etc.).
- Ensure the ByteBuffer position is at the value start (duplicate/rewind) so remaining() reflects the full value.
- Replace truncated/partial payloads at the source — the data itself is corrupt if genuinely < 4 bytes.
Example fix
// before
ByteBuffer b = ByteBuffer.allocate(2).putShort((short)3); // truncated
decimalCodec.deserialize(b, version); // throws
// after
byte[] unscaled = new BigInteger("12345").toByteArray();
ByteBuffer b = ByteBuffer.allocate(4 + unscaled.length).putInt(2).put(unscaled);
decimalCodec.deserialize(b, version); Defensive patterns
Strategy: validation
Validate before calling
if (bytes == null || bytes.remaining() < 4)
throw new IllegalArgumentException("decimal needs >= 4 bytes, got " + (bytes == null ? 0 : bytes.remaining())); Type guard
boolean isDecimalBuffer(ByteBuffer b) {
return b != null && b.remaining() >= 4;
} Try / catch
try {
return decimalCodec.deserialize(bytes, protocolVersion);
} catch (InvalidTypeException e) {
throw new IllegalStateException("Corrupt or wrong-typed decimal payload: " + bytes.remaining() + " bytes", e);
} Prevention
- Always serialize decimals as 4-byte scale + unscaled BigInteger bytes (use the codec's own serialize).
- Match codec to column type after any schema migration.
- Duplicate/reset the buffer position before decoding so remaining() covers the whole value.
When it happens
Trigger: Calling decimalCodec.deserialize(bytes, protocolVersion) where 0 < bytes.remaining() < 4 — e.g. decoding an int (4 bytes is OK, but 2-byte smallint isn't), float, or truncated buffer through the decimal codec.
Common situations: Schema changed from decimal to float/double/int while codecs assume decimal; truncated network or SSTable bytes; custom serialization writing only the unscaled bytes without the 4-byte scale prefix; misaligned buffer positions.
Related errors
- Invalid 64-bits long value, expecting 8 bytes but got
- Invalid boolean value, expecting 1 byte but got
- Cannot parse decimal value from "%s"
- text or varchar values must be enclosed by single quotes
- %s is not a valid ASCII String
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/8809f23b3af0bb97.
Report an issue: GitHub.