apache/iceberg · error · UnsupportedOperationException

Cannot convert unknown expression: ${expr}

Error message

Cannot convert unknown expression: ${expr}

What it means

Thrown by Spark3Util.toIcebergTerm when the input expression is neither a Transform nor a NamedReference. Iceberg terms can only be derived from column references or transforms, so any other Spark Expression subclass cannot be converted.

Source

Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java:438

                  .map(ref -> DOT.join(ref.fieldNames()))
                  .map(org.apache.iceberg.expressions.Expressions::ref)
                  .collect(Collectors.toList()));
        case "hilbert":
          return new Hilbert(
              Stream.of(transform.references())
                  .map(ref -> DOT.join(ref.fieldNames()))
                  .map(org.apache.iceberg.expressions.Expressions::ref)
                  .collect(Collectors.toList()));
        default:
          throw new UnsupportedOperationException("Transform is not supported: " + transform);
      }

    } else if (expr instanceof NamedReference) {
      NamedReference ref = (NamedReference) expr;
      return org.apache.iceberg.expressions.Expressions.ref(DOT.join(ref.fieldNames()));

    } else {
      throw new UnsupportedOperationException("Cannot convert unknown expression: " + expr);
    }
  }

  /**
   * Converts Spark transforms into a {@link PartitionSpec}.
   *
   * @param schema the table schema
   * @param partitioning Spark Transforms
   * @return a PartitionSpec
   */
  public static PartitionSpec toPartitionSpec(Schema schema, Transform[] partitioning) {
    if (partitioning == null || partitioning.length == 0) {
      return PartitionSpec.unpartitioned();
    }

    PartitionSpec.Builder builder = PartitionSpec.builderFor(schema);
    for (Transform transform : partitioning) {
      Preconditions.checkArgument(

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Ensure the expression is a plain column reference (NamedReference) or Transform
  2. Extract and pass the underlying column names instead of the computed expression
  3. Simplify the DDL so terms reference columns directly

Example fix

// before
Expressions.ref(exprToString(Literal.of(1)));
// after
Expressions.ref("column_name");
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(expr instanceof Transform) && !(expr instanceof NamedReference)) {
  throw new IllegalArgumentException("Expression must be a Transform or NamedReference");
}

Type guard

boolean isConvertibleTerm(Expression expr) {
  return expr instanceof Transform || expr instanceof NamedReference;
}

Try / catch

try {
  term = Spark3Util.toIcebergTerm(expr);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().startsWith("Cannot convert unknown expression")) {
    // extract column references from expr and retry
  }
}

Prevention

When it happens

Trigger: Passing computed/literal expressions (e.g. Literal, arithmetic expressions) into toIcebergTerm instead of a plain column reference or transform.

Common situations: Custom catalog code extracting terms from arbitrary Spark expressions; DDL features that embed expressions where Iceberg expects a bare column name.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/856cf49025635d57. Report an issue: GitHub.