prestodb/presto · error · IllegalArgumentException
Decimal out of bound:
Error message
Decimal out of bound:
What it means
checkDecimal is the precision/scale guard used by VariantUtil.getDecimal. The Variant encoding stores decimals as DECIMAL4/8/16 with a scale byte; the decoded BigDecimal must fit the maximum precision allowed for the backing integer width (4, 8, or 16 bytes). This IllegalArgumentException is thrown when the decoded decimal's precision exceeds maxPrecision or its scale exceeds maxPrecision, meaning the variant bytes encode a decimal this layout cannot legally represent.
Source
Thrown at presto-parquet/src/main/java/com/facebook/presto/parquet/spark/VariantUtil.java:317
// Get a double value from variant value `value[position...]`.
// Throw `MALFORMED_VARIANT` if the variant is malformed.
public static double getDouble(byte[] value, int position)
{
checkIndex(position, value.length);
int basicType = value[position] & BASIC_TYPE_MASK;
int typeInfo = (value[position] >> BASIC_TYPE_BITS) & TYPE_INFO_MASK;
if (basicType != PRIMITIVE || typeInfo != DOUBLE) {
throw unexpectedType(Type.DOUBLE);
}
return Double.longBitsToDouble(readLong(value, position + 1, 8));
}
// Check whether the precision and scale of the decimal are within the limit.
private static void checkDecimal(BigDecimal decimal, int maxPrecision)
{
if (decimal.precision() > maxPrecision || decimal.scale() > maxPrecision) {
throw new IllegalArgumentException("Decimal out of bound: " + decimal);
}
}
// Get a decimal value from variant value `value[position...]`.
// Throw `MALFORMED_VARIANT` if the variant is malformed.
public static BigDecimal getDecimal(byte[] value, int position)
{
checkIndex(position, value.length);
int basicType = value[position] & BASIC_TYPE_MASK;
int typeInfo = (value[position] >> BASIC_TYPE_BITS) & TYPE_INFO_MASK;
if (basicType != PRIMITIVE) {
throw unexpectedType(Type.DECIMAL);
}
// Interpret the scale byte as unsigned. If it is a negative byte, the unsigned value must be
// greater than `MAX_DECIMAL16_PRECISION` and will trigger an error in `checkDecimal`.
int scale = value[position + 1] & 0xFF;
BigDecimal result;
switch (typeInfo) {View on GitHub (pinned to 55bb57d202)
Solutions
- Regenerate or re-read the source data to rule out corruption in the variant decimal payload
- Check the writing engine's Variant decimal encoding matches the spec (scale byte + little-endian unscaled value within width)
- Validate the decoded BigDecimal's precision/scale bounds yourself before use and reject malformed rows
- Catch IllegalArgumentException around getDecimal and skip/log the offending row
Example fix
// before
BigDecimal d = VariantUtil.getDecimal(value, pos);
// after
BigDecimal d;
try {
d = VariantUtil.getDecimal(value, pos);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Malformed variant decimal in row", e);
} Defensive patterns
Strategy: validation
Validate before calling
// Java
static boolean isDecimalInBound(BigDecimal d, int maxPrecision) {
return d.precision() <= maxPrecision && d.scale() <= maxPrecision;
}
// call before relying on the decoded value:
// isDecimalInBound(decoded, 38) // 128-bit variant decimal limit Try / catch
// Java
try {
BigDecimal d = VariantUtil.getDecimal(value, pos);
} catch (IllegalArgumentException e) {
// reject the row as malformed variant decimal
} Prevention
- Only decode decimals with the width (4/8/16) matching the variant type code
- Sanity-check decoded precision/scale against the spec limits before use
- Verify the writing engine conforms to the Variant decimal encoding spec
- Log and quarantine corrupt rows instead of failing the whole scan
When it happens
Trigger: Calling VariantUtil.getDecimal(byte[] value, int position) on a variant whose DECIMAL4/DECIMAL8/DECIMAL16 payload decodes to a BigDecimal with precision > maxPrecision (32/64/128 as per the calling width) or scale > maxPrecision — i.e. corrupt or out-of-spec variant bytes.
Common situations: Variant data written by a non-conforming writer; corrupted decimal payload bytes; manually decoding raw variant bytes with the wrong assumed width so the decoded value overflows the allowed precision.
Related errors
- Unexpected type:
- Index out of bound: %s (size: %s)
- Invalid offset: %s > %s
- DECIMAL precision must be in range [1, 38]
- DECIMAL scale must be in range [0, precision]
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/7134dad0ebad2de6.
Report an issue: GitHub.