apache/iceberg · error · java.lang.UnsupportedOperationException
Cannot convert type to SQL: %s
Error message
Cannot convert type to SQL: %s
What it means
Spark3Util's DescribeExpressionVisitor converts Iceberg types to Spark SQL type strings; this UnsupportedOperationException is thrown for any PrimitiveType not handled by the visitor's switch (all standard types are handled, so this fires only for exotic or future primitive types).
Source
Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java:610
case DOUBLE:
return "double";
case DATE:
return "date";
case TIME:
return "time";
case TIMESTAMP:
return "timestamp";
case STRING:
case UUID:
return "string";
case FIXED:
case BINARY:
return "binary";
case DECIMAL:
Types.DecimalType decimal = (Types.DecimalType) primitive;
return "decimal(" + decimal.precision() + "," + decimal.scale() + ")";
}
throw new UnsupportedOperationException("Cannot convert type to SQL: " + primitive);
}
}
private static class DescribeExpressionVisitor
extends ExpressionVisitors.ExpressionVisitor<String> {
private static final DescribeExpressionVisitor INSTANCE = new DescribeExpressionVisitor();
private DescribeExpressionVisitor() {}
@Override
public String alwaysTrue() {
return "true";
}
@Override
public String alwaysFalse() {
return "false";
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Upgrade the Iceberg Spark runtime to a version whose DescribeExpressionVisitor covers the primitive type in the schema
- Identify the offending type via the message text and rewrite the column type (e.g. via migration) to a supported primitive
- Copy the DescribeTypeVisitor logic and add a case for the missing type in a local fork
Example fix
// before
throw new UnsupportedOperationException("Cannot convert type to SQL: " + primitive);
// after
case TIMESTAMP_NANO:
return "timestamp_ntz";
default:
throw new UnsupportedOperationException("Cannot convert type to SQL: " + primitive); Defensive patterns
Strategy: validation
Validate before calling
if (type instanceof Types.PrimitiveType p && !SUPPORTED_SQL_PRIMITIVES.contains(p.typeId())) {
throw new IllegalArgumentException("Type not renderable as SQL: " + p);
} Type guard
boolean isSupportedPrimitive(Type t) { return t.isPrimitiveType() && KNOWN_TYPE_IDS.contains(t.typeId()); } Try / catch
try { return Spark3Util.describeType(type); } catch (UnsupportedOperationException e) { log.warn("SQL rendering unsupported: {}", e.getMessage()); return type.toString(); } Prevention
- Keep the Iceberg Spark runtime version aligned with the library that wrote the schema
- Check the type against TypeID before rendering to SQL
- Avoid custom/future primitive types in schemas rendered via describeType
When it happens
Trigger: Calling Spark3Util.describeType (via DESCRIBE TABLE / schema-to-SQL conversion) with a PrimitiveType case missing from the visitor's switch, e.g. a new primitive added to the Iceberg spec but not yet mapped here.
Common situations: Using a table whose schema contains a primitive type the installed Iceberg Spark module version doesn't know how to render; forward/backward version mismatch between writer and reader libraries.
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
- Expected truncation col to be tinyint, shortint, int, bigint
- Cannot convert bound predicates to SQL
- Cannot convert predicate to SQL: %s
- Cannot convert term to SQL: %s
- Cannot use column %s of type %s in ZOrdering, the type is un
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/6f86f36d01b11062.
Report an issue: GitHub.