apache/iceberg · error · UnsupportedOperationException
Unknown transform class %s
Error message
Unknown transform class %s
What it means
PartitionSpecVisitor.visit() throws this after exhausting its instanceof dispatch over all known transform classes (Identity, Bucket, Truncate, Years/Months/Days/Hours, VoidTransform, UnknownTransform and the legacy Dates/Timestamps singletons). Hitting it means a PartitionField's transform is an object of a class the visitor dispatcher does not recognize at all — distinct from the per-transform default hooks, this is a dispatch-level failure inside Iceberg itself.
Source
Thrown at api/src/main/java/org/apache/iceberg/transforms/PartitionSpecVisitor.java:149
|| transform == Timestamps.NANOS_TO_MONTH
|| transform instanceof Months) {
return visitor.month(field.fieldId(), sourceName, field.sourceId());
} else if (transform == Dates.DAY
|| transform == Timestamps.MICROS_TO_DAY
|| transform == Timestamps.NANOS_TO_DAY
|| transform instanceof Days) {
return visitor.day(field.fieldId(), sourceName, field.sourceId());
} else if (transform == Timestamps.MICROS_TO_HOUR
|| transform == Timestamps.NANOS_TO_HOUR
|| transform instanceof Hours) {
return visitor.hour(field.fieldId(), sourceName, field.sourceId());
} else if (transform instanceof VoidTransform) {
return visitor.alwaysNull(field.fieldId(), sourceName, field.sourceId());
} else if (transform instanceof UnknownTransform) {
return visitor.unknown(field.fieldId(), sourceName, field.sourceId(), transform.toString());
}
throw new UnsupportedOperationException(
String.format("Unknown transform class %s", field.transform().getClass().getName()));
}
}
View on GitHub (pinned to 86d9c8fc54)
Solutions
- Ensure all Iceberg modules use the same version — check the classpath for duplicate/conflicting iceberg-api jars (mvn dependency:tree)
- If you ship a custom Transform subclass, it cannot be dispatched here; convert the spec field to a standard transform or extend the visitor dispatch path upstream
- Reproduce with field.transform().getClass().getName() from the message to identify the offending class and its jar
Example fix
// before Transform myTransform = new MyCustomTransform(); // not dispatched by visit() // after Transforms.identity() // or another standard transform (bucket/truncate/year/...) known to visit()
Defensive patterns
Strategy: validation
Validate before calling
// Detect non-standard transform classes before dispatch:
Set<String> known = Set.of("Identity", "Bucket", "Truncate", "Years", "Months", "Days",
"Hours", "VoidTransform", "UnknownTransform");
for (PartitionField f : spec.fields()) {
String cls = f.transform().getClass().getSimpleName();
if (!known.contains(cls)) throw new IllegalStateException("Non-standard transform: " + cls);
} Type guard
if (!(field.transform() instanceof Identity || field.transform() instanceof Bucket
|| field.transform() instanceof Truncate || field.transform() instanceof VoidTransform
|| field.transform() instanceof UnknownTransform
|| field.transform() instanceof Years || field.transform() instanceof Months
|| field.transform() instanceof Days || field.transform() instanceof Hours)) {
throw new IllegalStateException("Unsupported transform class: " + field.transform().getClass());
} Try / catch
try {
PartitionSpecVisitor.visit(spec, visitor);
} catch (UnsupportedOperationException e) {
if (e.getMessage().startsWith("Unknown transform class")) {
throw new IllegalStateException("Mixed Iceberg versions or custom transform on classpath", e);
}
throw e;
} Prevention
- Keep all iceberg-* artifacts at one version; run mvn dependency:tree to detect conflicts
- Avoid custom Transform subclasses in persisted specs — stick to Transforms.* factories
- Log field.transform().getClass().getName() when this fires to identify the offending jar
When it happens
Trigger: A PartitionField carries a Transform instance outside the known set — typically a user-defined Transform subclass implementation, or a class from a different/patched Iceberg version placed on the classpath, passed to PartitionSpecVisitor.visit(schema, field, visitor).
Common situations: Custom Transform implementations registered via custom serialization on the writer side; mixed Iceberg jar versions (shaded vs non-shaded, vendor forks) so the same logical transform fails instanceof checks; third-party catalogs injecting custom transform objects into specs.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Unknown transform %s is not supported
- Cannot replace transform in unknown predicate: + pred
- Unknown transform %s is not supported
- Can't retrieve values from an empty struct
- Can't modify an empty struct
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/8bc4f480b18d37da.
Report an issue: GitHub.