apache/seatunnel · error · IllegalArgumentException

Expected Column expression, but got

Error message

Expected Column expression, but got: ${expr.getClass().getSimpleName()}

What it means

safeGetColumn requires the left-hand side of a comparison/IN expression to be a plain JSqlParser Column. Expressions such as function calls, casts, arithmetic, or literals on the left side are rejected because the converter can only resolve a column name to a Paimon predicate index.

Solutions

  1. Rewrite the predicate so a bare column is on the left: name='a' instead of UPPER(name)='A'.
  2. Remove CASTs and use literals matching the column type.
  3. Move function-based filtering to post-read processing or a transform.
  4. Normalize reversed comparisons (swap operands) before conversion.

Example fix

// before: WHERE UPPER(name) = 'JOHN' | // after: WHERE name = 'JOHN' (or filter after read)
Defensive patterns

Strategy: validation

Validate before calling

if (e instanceof BinaryExpression) { Expression left = ((BinaryExpression) e).getLeftExpression(); if (!(left instanceof Column)) throw new IllegalArgumentException("Left side must be a bare column"); }

Type guard

boolean isColumn(Expression e) { return e instanceof Column; }

Try / catch

try { pred = converter.convertSqlWhereToPaimonPredicate(where, rowType); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Expected Column")) { /* push filter to post-read */ } throw e; }

Prevention

When it happens

Trigger: WHERE clause with a non-column left operand: UPPER(name)='A', CAST(id AS VARCHAR)='5', id+1=3, or a reversed comparison like 'a' = col.

Common situations: Users applying functions in filters expecting pushdown; literal-first comparisons; CASTs inserted by SQL dialect adapters.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/06b47588fa8f3cec. Report an issue: GitHub.

Appendix: source

Thrown at seatunnel-connectors-v2/connector-paimon/src/main/java/org/apache/seatunnel/connectors/seatunnel/paimon/source/converter/SqlToPaimonPredicateConverter.java:351

            Object rawVal = getJSQLParserDataTypeValue(expression);
            if (rawVal == null) {
                throw new IllegalArgumentException("Null value found in IN clause values");
            }
            Object convertedVal =
                    convertValueByPaimonDataType(rowType, column.getColumnName(), rawVal);
            if (convertedVal == null) {
                throw new IllegalArgumentException(
                        "Failed to convert value in IN clause: " + rawVal);
            }
            values.add(convertedVal);
        }

        return expr.isNot() ? builder.notIn(index, values) : builder.in(index, values);
    }

    private static Column safeGetColumn(Expression expr) {
        if (!(expr instanceof Column)) {
            throw new IllegalArgumentException(
                    "Expected Column expression, but got: " + expr.getClass().getSimpleName());
        }
        return (Column) expr;
    }

    private static Object convertValueByPaimonDataType(
            RowType rowType, String columnName, Object jsqlParserDataTypeValue) {
        Optional<DataField> theFiled =
                rowType.getFields().stream()
                        .filter(field -> field.name().equalsIgnoreCase(columnName.replace("`", "")))
                        .findFirst();
        String strValue = jsqlParserDataTypeValue.toString();
        if (theFiled.isPresent()) {
            DataType dataType = theFiled.get().type();
            switch (dataType.getTypeRoot()) {
                case CHAR:
                case VARCHAR:
                    return jsqlParserDataTypeValue;

View on GitHub (pinned to cf67b549a7)