apache/iceberg · error · UnsupportedOperationException
Cannot convert type to SQL:
Error message
Cannot convert type to SQL:
What it means
Spark3Util.DescribeExpressionVisitor.primitive maps Iceberg primitive types to SQL type strings for DESCRIBE output. The switch covers boolean, integer types, float/double, date, timestamp, string, uuid, fixed, binary and decimal; anything else (or an unexpected Type) throws UnsupportedOperationException 'Cannot convert type to SQL'.
Solutions
- Check the schema type reported in the message; map it to a supported primitive (e.g. use string/uuid/fixed/binary/decimal equivalents)
- Upgrade the Iceberg Spark module so its type-to-SQL mapping covers the type
- Patch Spark3Util to add a case for the new type in the switch
Example fix
// before
throw new UnsupportedOperationException("Cannot convert type to SQL: " + primitive);
// after
case TIMESTAMP_NANO:
return "timestamp_ntz"; // add case before the throw
// or
return primitive.toString(); // degrade instead of throwing Defensive patterns
Strategy: type-guard
Validate before calling
Types.TypeID id = ((Types.PrimitiveType) type).typeId();
Set<Types.TypeID> known = Set.of(BOOLEAN, INTEGER, LONG, FLOAT, DOUBLE, DATE,
TIMESTAMP, STRING, UUID, FIXED, BINARY, DECIMAL);
if (!known.contains(id)) throw new IllegalArgumentException("Type not renderable as SQL: " + type); Type guard
boolean isRenderable(Types.Type t) {
return t instanceof Types.PrimitiveType && !t.equals(Types.TimestampNanoType.get());
} Try / catch
try {
String sql = primitive(type);
} catch (UnsupportedOperationException e) {
return type.toString(); // degrade to Iceberg type name in DESCRIBE output
} Prevention
- Keep the Iceberg Spark module at the same version as core to cover all primitive types
- Handle nano-timestamps and new types explicitly in custom describe tooling
- Test DESCRIBE output against schemas containing every primitive type you emit
When it happens
Trigger: DESCRIBE TABLE on an Iceberg table whose schema contains a primitive type not handled by the visitor's switch — typically a newer Iceberg type added after this Spark v4.0 helper was written, or a nested/type dispatch bug passing a non-primitive into primitive().
Common situations: Schema written by a newer Iceberg version read by an older Spark connector; custom Type implementations; directly invoking Spark3Util.describeSchema on hand-built schemas.
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
- Cannot convert Spark geography with mixed SRID to Iceberg
- Cannot convert Spark geography with mixed SRID to Iceberg
- Cannot convert Spark geometry with mixed SRID to Iceberg
- Cannot convert Spark geometry with mixed SRID to Iceberg
- Cannot convert type to SQL
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/8caf0e51834365a0.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java:614
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)