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
- Ensure the expression is a plain column reference (NamedReference) or Transform
- Extract and pass the underlying column names instead of the computed expression
- 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
- Pass column names/transforms, never computed expressions
- Extract NamedReferences from complex expressions before conversion
- Reject non-reference expressions early in DDL tooling
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
- Cannot convert bound predicates to SQL
- Cannot convert predicate to SQL: %s
- Cannot convert term to SQL: %s
- Cannot convert bound predicates to SQL
- Invalid aggregate:
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/856cf49025635d57.
Report an issue: GitHub.