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

  1. Regenerate or re-read the source data to rule out corruption in the variant decimal payload
  2. Check the writing engine's Variant decimal encoding matches the spec (scale byte + little-endian unscaled value within width)
  3. Validate the decoded BigDecimal's precision/scale bounds yourself before use and reject malformed rows
  4. 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

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


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/7134dad0ebad2de6. Report an issue: GitHub.