prestodb/presto · warning · IllegalArgumentException

Can't convert value to long:

Error message

Can't convert value to long: 

What it means

asLong converts Parquet statistic values (min/max) to long for integer-family types (BIGINT, INTEGER, SMALLINT, TINYINT). It accepts only Byte/Short/Integer/Long; any other value class (e.g. BigDecimal, BigInteger, String from odd statistic decoders) is rejected with IllegalArgumentException naming the actual class.

Source

Thrown at presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/TupleDomainParquetPredicate.java:270

        int dictionarySize = dictionaryPage.get().getDictionarySize();
        DictionaryValueConverter converter = new DictionaryValueConverter(dictionary);
        Function<Integer, Object> convertFunction = converter.getConverter(columnDescriptor.getPrimitiveType());
        List<Object> values = new ArrayList<>();
        for (int i = 0; i < dictionarySize; i++) {
            values.add(convertFunction.apply(i));
        }

        // TODO: when min == max (i.e., singleton ranges, the construction of Domains can be done more efficiently
        return getDomain(columnDescriptor, type, values, values, true);
    }

    public static long asLong(Object value)
    {
        if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
            return ((Number) value).longValue();
        }

        throw new IllegalArgumentException("Can't convert value to long: " + value.getClass().getName());
    }

    private static <T extends Comparable<T>> Domain createDomain(Type type, ColumnIndex columnIndex, boolean hasNullValue, List<T> mins, List<T> maxs)
    {
        if (mins.isEmpty() || maxs.isEmpty() || mins.size() != maxs.size()) {
            return Domain.create(ValueSet.all(type), hasNullValue);
        }
        int pageCount = columnIndex.getMinValues().size();
        List<Range> ranges = new ArrayList<>();
        for (int i = 0; i < pageCount; i++) {
            T min = mins.get(i);
            T max = maxs.get(i);
            if (min.compareTo(max) > 0) {
                return Domain.create(ValueSet.all(type), hasNullValue);
            }

            if (min instanceof Long) {
                if (isStatisticsOverflow(type, asLong(min), asLong(max))) {

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Ensure the parquet statistics deserialization matches the column physical type (upgrade/align parquet library versions)
  2. Check whether the column's declared type was altered (e.g. INT64 read as DECIMAL) and re-map it correctly
  3. Validate file statistics with parquet-tools; rewrite the file if the stats are corrupt
  4. Catch the IllegalArgumentException where statistics are consumed and fall back to an all-values domain

Example fix

// before
throw new IllegalArgumentException("Can't convert value to long: " + value.getClass().getName());
// after
if (value instanceof Number) {
    return ((Number) value).longValue();
}
if (value instanceof BigInteger) {
    return ((BigInteger) value).longValueExact();
}
throw new IllegalArgumentException("Can't convert value to long: " + value.getClass().getName());
Defensive patterns

Strategy: type-guard

Validate before calling

// check statistic value classes before domain construction
if (stats.getMin() != null && !(stats.getMin() instanceof Number)) {
    skipPredicatePushdown(column); // fall back to full scan
}

Type guard

boolean isIntegralStat(Object v) {
    return v instanceof Byte || v instanceof Short || v instanceof Integer || v instanceof Long;
}

Try / catch

try {
    domain = TupleDomainParquetPredicate.asLong(minStat);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Can't convert value to long")) {
        domain = Domain.create(ValueSet.all(BIGINT), true);
    } else throw e;
}

Prevention

When it happens

Trigger: TupleDomainParquetPredicate builds domains for BIGINT/TINYINT/SMALLINT/INTEGER columns and calls asLong on a statistics minimum/maximum whose runtime type is not one of Byte, Short, Integer, or Long — i.e. the statistics deserializer produced an unexpected boxed type.

Common situations: Statistics decoded by a mismatched parquet reader version producing BigInteger/BigDecimal for INT64; corrupted statistics blobs decoded as strings; custom type mappings where min/max are deserialized differently than expected.

Related errors


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