prestodb/presto · error · IllegalArgumentException
Unexpected decimal type:
Error message
Unexpected decimal type:
What it means
TpcdsTableStatisticsFactory.toDouble converts a decoded statistics value to double; for decimal values it only handles short (64-bit) and long (128-bit) decimals via isShortDecimal/isLongDecimal. A decimal value that is neither, or a DecimalType variant it does not recognize, triggers 'Unexpected decimal type'. It is an internal invariant violation in statistics conversion.
Source
Thrown at presto-tpcds/src/main/java/com/facebook/presto/tpcds/statistics/TpcdsTableStatisticsFactory.java:112
}
private static double toDouble(Object value, Type type)
{
if (value instanceof String && type.equals(DATE)) {
return LocalDate.parse((CharSequence) value).toEpochDay();
}
if (type.equals(BIGINT) || type.equals(INTEGER) || type.equals(DATE)) {
return ((Number) value).doubleValue();
}
if (type instanceof DecimalType) {
DecimalType decimalType = (DecimalType) type;
if (isShortDecimal(decimalType)) {
return parseDouble(Decimals.toString(((Number) value).longValue(), decimalType.getScale()));
}
if (isLongDecimal(decimalType)) {
return parseDouble(Decimals.toString((Slice) value, decimalType.getScale()));
}
throw new IllegalArgumentException("Unexpected decimal type: " + decimalType);
}
if (type.equals(DOUBLE)) {
return ((Number) value).doubleValue();
}
throw new IllegalArgumentException("unsupported column type " + type);
}
}
View on GitHub (pinned to 55bb57d202)
Solutions
- Ensure statistics blocks use standard Presto DecimalType instances (createDecimalType)
- Check the decimalType precision is within 1..38 so short/long classification works
- Upgrade Presto if a type-system change broke isShortDecimal/isLongDecimal classification
- Report/investigate which plugin supplied the non-standard decimal type
Example fix
// before Type t = new MyCustomDecimalType(p, s); // after Type t = DecimalType.createDecimalType(p, s);
Defensive patterns
Strategy: type-guard
Validate before calling
if (type instanceof DecimalType) {
DecimalType d = (DecimalType) type;
if (d.getPrecision() < 1 || d.getPrecision() > 38) {
throw new IllegalArgumentException("Decimal precision out of range: " + d);
}
} else if (!type.equals(DOUBLE)) {
throw new IllegalArgumentException("Stats conversion requires decimal or double, got " + type);
} Type guard
boolean isSupportedNumeric(Type t) {
return t.equals(DOUBLE) || (t instanceof DecimalType && ((DecimalType) t).getPrecision() <= 38);
} Try / catch
try {
double d = toDouble(type, value);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Unexpected decimal type")) {
throw new IllegalStateException("Non-standard decimal type in stats block: " + e.getMessage(), e);
}
throw e;
} Prevention
- Use DecimalType.createDecimalType for all decimal stats columns
- Keep precision within 1..38 so short/long classification holds
- Avoid custom Type implementations in statistics paths
When it happens
Trigger: toRange building a stats range from a column block value typed as decimal but whose Type instance is not classified as short or long decimal (e.g. an unexpected DecimalType implementation or precision outside 1-38).
Common situations: Custom or third-party Type implementations for decimals feeding statistics conversion; internal Presto type-system changes; statistics blocks built with mismatched type metadata.
Related errors
- Unexpected decimal type: ${decimalType}
- unsupported column type
- unsupported column type
- TABLE_NOT_FOUND
- NOT_SUPPORTED
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/47a13e712064e66a.
Report an issue: GitHub.