prestodb/presto · error · UnsupportedOperationException

Can't handle type:

Error message

Can't handle type: 

What it means

QueryBuilder.buildSql() binds predicate/bucket values into the generated SQL; it handles boolean, bigint, integer, smallint, tinyint, double, real, varchar and char types explicitly. Any other Presto type used in a pushdown predicate (e.g. date, timestamp, decimal, varbinary) throws UnsupportedOperationException "Can't handle type: ...".

Source

Thrown at presto-clickhouse/src/main/java/com/facebook/presto/plugin/clickhouse/QueryBuilder.java:223

                statement.setTime(i + 1, new Time((long) typeAndValue.getValue()));
            }
            else if (typeAndValue.getType().equals(TIME_WITH_TIME_ZONE)) {
                statement.setTime(i + 1, new Time(unpackMillisUtc((long) typeAndValue.getValue())));
            }
            else if (typeAndValue.getType().equals(TIMESTAMP)) {
                statement.setTimestamp(i + 1, new Timestamp((long) typeAndValue.getValue()));
            }
            else if (typeAndValue.getType().equals(TIMESTAMP_WITH_TIME_ZONE)) {
                statement.setTimestamp(i + 1, new Timestamp(unpackMillisUtc((long) typeAndValue.getValue())));
            }
            else if (typeAndValue.getType() instanceof VarcharType) {
                statement.setString(i + 1, ((Slice) typeAndValue.getValue()).toStringUtf8());
            }
            else if (typeAndValue.getType() instanceof CharType) {
                statement.setString(i + 1, ((Slice) typeAndValue.getValue()).toStringUtf8());
            }
            else {
                throw new UnsupportedOperationException("Can't handle type: " + typeAndValue.getType());
            }
        }

        return statement;
    }

    private static boolean isAcceptedType(Type type)
    {
        Type validType = requireNonNull(type, "type is null");
        return validType.equals(BIGINT) ||
                validType.equals(TINYINT) ||
                validType.equals(SMALLINT) ||
                validType.equals(INTEGER) ||
                validType.equals(DOUBLE) ||
                validType.equals(REAL) ||
                validType.equals(BOOLEAN) ||
                validType.equals(DATE) ||
                validType.equals(TIME) ||

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Cast the literal to a handled type or compare via string/numeric conversion, e.g. WHERE ts = TIMESTAMP '...' → use a cast of the column
  2. Rewrite the predicate so the unhandled type is not pushed as a literal (e.g. cast the column to VARCHAR)
  3. Disable predicate pushdown for that query by wrapping the filter so the connector filters locally
  4. Upgrade the connector — the handled-type list grows over versions

Example fix

// before
SELECT * FROM ch.db.t WHERE d = DATE '2024-01-01';
// after
SELECT * FROM ch.db.t WHERE CAST(d AS VARCHAR) = '2024-01-01';
Defensive patterns

Strategy: type-guard

Validate before calling

// Pre-check predicate types eligible for pushdown binding
Set<Class<?>> bindable = Set.of(Boolean.class, Long.class, Double.class, Float.class, Slice.class /*varchar/char*/);
Type t = predicateType;
boolean pushable = t instanceof BooleanType || t instanceof BigintType || t instanceof IntegerType
    || t instanceof SmallintType || t instanceof TinyintType || t instanceof DoubleType
    || t instanceof RealType || t instanceof VarcharType || t instanceof CharType;
if (!pushable) throw new IllegalArgumentException("Predicate on " + t + " cannot be pushed to ClickHouse; cast or filter locally");

Type guard

boolean isPredicateBindableToClickHouse(Type t) {
    return t instanceof BooleanType || t instanceof BigintType || t instanceof IntegerType
        || t instanceof SmallintType || t instanceof TinyintType || t instanceof DoubleType
        || t instanceof RealType || t instanceof VarcharType || t instanceof CharType;
}

Try / catch

try {
    executeWithPushdown(...);
} catch (UnsupportedOperationException e) {
    if (e.getMessage().startsWith("Can't handle type:")) {
        // re-run with the predicate evaluated locally (disable pushdown)
    } else throw e;
}

Prevention

When it happens

Trigger: Running a query whose WHERE clause contains a comparison predicate on a column type the ClickHouse QueryBuilder cannot bind (date, timestamp, decimal, varbinary, etc.), causing that predicate value to reach the unsupported else branch.

Common situations: Filtering on DATE/TIMESTAMP columns with literal comparisons; predicates pushed down after optimization; decimal comparisons from other catalogs joined against ClickHouse tables.

Related errors


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