apache/iceberg · error · java.lang.UnsupportedOperationException

Cannot convert predicate to SQL: <pred>

Error message

Cannot convert predicate to SQL: <pred>

What it means

Spark3Util's predicate-to-SQL converter (used by DESCRIBE TABLE / expression description) does not have a rendering rule for every Iceberg predicate kind. When it encounters a predicate case it does not handle (anything outside the enumerated cases like EQ, LT, LIKE, IN, etc.), it throws this UnsupportedOperationException.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java:716

          return sqlString(pred.term()) + " <= " + sqlString(pred.literal());
        case GT:
          return sqlString(pred.term()) + " > " + sqlString(pred.literal());
        case GT_EQ:
          return sqlString(pred.term()) + " >= " + sqlString(pred.literal());
        case EQ:
          return sqlString(pred.term()) + " = " + sqlString(pred.literal());
        case NOT_EQ:
          return sqlString(pred.term()) + " != " + sqlString(pred.literal());
        case STARTS_WITH:
          return sqlString(pred.term()) + " LIKE '" + pred.literal().value() + "%'";
        case NOT_STARTS_WITH:
          return sqlString(pred.term()) + " NOT LIKE '" + pred.literal().value() + "%'";
        case IN:
          return sqlString(pred.term()) + " IN (" + sqlString(pred.literals()) + ")";
        case NOT_IN:
          return sqlString(pred.term()) + " NOT IN (" + sqlString(pred.literals()) + ")";
        default:
          throw new UnsupportedOperationException("Cannot convert predicate to SQL: " + pred);
      }
    }

    private static <T> String sqlString(UnboundTerm<T> term) {
      if (term instanceof org.apache.iceberg.expressions.NamedReference) {
        return term.ref().name();
      } else if (term instanceof UnboundTransform) {
        UnboundTransform<?, ?> transform = (UnboundTransform<?, ?>) term;
        return transform.transform().toString() + "(" + transform.ref().name() + ")";
      } else {
        throw new UnsupportedOperationException("Cannot convert term to SQL: " + term);
      }
    }

    private static <T> String sqlString(List<org.apache.iceberg.expressions.Literal<T>> literals) {
      return literals.stream()
          .map(DescribeExpressionVisitor::sqlString)
          .collect(Collectors.joining(", "));

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Identify the predicate type printed in the message and express it with a supported predicate kind (e.g. rewrite STARTS_WITH as LIKE 'prefix%' manually).
  2. Upgrade or downgrade Iceberg's Spark runtime to a version whose converter supports the predicate kind you use.
  3. Wrap the call and fall back to pred.toString() or skip SQL rendering for unsupported predicates.
  4. If the predicate kind should be supported, add a case for it in Spark3Util's switch and contribute the fix upstream.

Example fix

// before
filter = new StartsWith("col", "abc");
String sql = Spark3Util.toSqlString(filter); // throws
// after
filter = Expressions.like("col", "abc%");
String sql = Spark3Util.toSqlString(filter);
Defensive patterns

Strategy: try-catch

Validate before calling

// Java
if (pred.op() != Expression.Operation.EQ && pred.op() != Expression.Operation.LT /* ...supported ops... */) {
  throw new IllegalArgumentException("Unsupported pred for SQL rendering: " + pred.op());
}

Type guard

boolean renderable(Expression pred) {
  switch (pred.op()) {
    case IS_NULL: case NOT_NULL: case LT: case LTE: case GT: case GTE: case EQ:
    case NOT_EQ: case IN: case NOT_IN: case LIKE: case NOT_LIKE:
      return true;
    default:
      return false;
  }
}

Try / catch

try {
  String sql = Spark3Util.toSqlString(pred);
} catch (UnsupportedOperationException e) {
  logger.warn("Falling back to toString for pred: {}", pred);
  sql = pred.toString();
}

Prevention

When it happens

Trigger: Calling DescribeExpressionVisitor/Spark3Util SQL rendering on a predicate whose op() falls into the default branch of the switch — e.g. an unsupported or newly added predicate type such as STARTS_WITH, NOT_STARTS_WITH, or a predicate kind from a newer Iceberg expression set passed into a Spark SQL conversion path.

Common situations: Using expression-based SQL description of Iceberg filters after an Iceberg upgrade added new predicate types; passing custom or exotic predicates (e.g. derived predicates from pushed-down filters) into catalog filter rendering.

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/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/142c68b640705b48. Report an issue: GitHub.