apache/iceberg · error · UnsupportedOperationException
Void transform is not supported
Error message
Void transform is not supported
What it means
PartitionSpecVisitor's default alwaysNull() throws UnsupportedOperationException for partition fields using the Void transform. A Void transform results from partition-field evolution: a field is removed from the spec by replacing its transform with void, leaving the column all nulls. Dispatch in visit() matches VoidTransform and calls alwaysNull(); implementations that ignore void fields fail here unless they explicitly handle them.
Solutions
- Override alwaysNull(int fieldId, String sourceName, int sourceId) to emit the appropriate representation (e.g. a null-valued partition column or skip the field)
- Filter spec.fields() for transform instanceof VoidTransform before visiting and decide how to map them
- If the target cannot represent void partition fields, remap or drop them in the visitor implementation explicitly
Example fix
// before
visitor without alwaysNull override -> UnsupportedOperationException on evolved spec
// after
@Override
public String alwaysNull(int fieldId, String sourceName, int sourceId) {
return null; // void partition field: all values are null
} Defensive patterns
Strategy: validation
Validate before calling
boolean hasVoidTransform(PartitionSpec spec) {
return spec.fields().stream().anyMatch(f -> f.transform() instanceof VoidTransform);
}
// indicates an evolved spec; decide before visiting how void fields map Type guard
if (field.transform() instanceof VoidTransform) {
// emit null representation or skip — do not rely on the throwing default
} Try / catch
try {
PartitionSpecVisitor.visit(spec, visitor);
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("Void")) {
LOG.warn("Spec has void partition fields (partition evolution); adjust visitor");
}
throw e;
} Prevention
- Remember specs evolve: removed fields become void, so old visitors break on old tables
- Always override alwaysNull() in production visitors
- Round-trip test: evolve a spec (remove a field), then run the visitor
When it happens
Trigger: PartitionSpecVisitor.visit on a table whose partition spec contains a void transform — i.e. a partition field was removed via updatePartitionSpec/removeField and later the spec is visited by a visitor without an alwaysNull override.
Common situations: Tables whose partitioning was evolved (dropped/changed partition fields) visited by catalog translators that were written for specs with only live transforms; copying such a spec to a target catalog that cannot represent void fields.
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
- Bucket transform is not supported
- Cannot bind unsupported transform
- Cannot bucket by type:
- Day transform is not supported
- Hour transform is not supported
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/d0e5e4934d7f2482.
Report an issue: GitHub.
Appendix: source
Thrown at api/src/main/java/org/apache/iceberg/transforms/PartitionSpecVisitor.java:85
default T day(int fieldId, String sourceName, int sourceId) {
return day(sourceName, sourceId);
}
default T day(String sourceName, int sourceId) {
throw new UnsupportedOperationException("Day transform is not supported");
}
default T hour(int fieldId, String sourceName, int sourceId) {
return hour(sourceName, sourceId);
}
default T hour(String sourceName, int sourceId) {
throw new UnsupportedOperationException("Hour transform is not supported");
}
default T alwaysNull(int fieldId, String sourceName, int sourceId) {
throw new UnsupportedOperationException("Void transform is not supported");
}
default T unknown(int fieldId, String sourceName, int sourceId, String transform) {
throw new UnsupportedOperationException(
String.format("Unknown transform %s is not supported", transform));
}
/**
* Visit the fields of a {@link PartitionSpec}.
*
* @param spec a partition spec to visit
* @param visitor a partition spec visitor
* @param <R> return type of the visitor
* @return a list of the result produced by visiting each partition field
*/
static <R> List<R> visit(PartitionSpec spec, PartitionSpecVisitor<R> visitor) {
List<R> results = Lists.newArrayListWithExpectedSize(spec.fields().size());
View on GitHub (pinned to 86d9c8fc54)