apache/iceberg · error · UnsupportedOperationException
Unsupported delete granularity: <granularity>
Error message
Unsupported delete granularity: <granularity>
What it means
ClusteredPositionDeleteWriter.newWriter only supports FILE and PARTITION delete granularities; any other DeleteGranularity value (e.g., null or a new enum constant from a newer Iceberg version) hits the default branch and throws UnsupportedOperationException.
Source
Thrown at core/src/main/java/org/apache/iceberg/io/ClusteredPositionDeleteWriter.java:79
this.writerFactory = writerFactory;
this.fileFactory = fileFactory;
this.io = io;
this.targetFileSizeInBytes = targetFileSizeInBytes;
this.granularity = granularity;
this.deleteFiles = Lists.newArrayList();
this.referencedDataFiles = CharSequenceSet.empty();
}
@Override
protected FileWriter<PositionDelete<T>, DeleteWriteResult> newWriter(
PartitionSpec spec, StructLike partition) {
switch (granularity) {
case FILE:
return new FileScopedPositionDeleteWriter<>(() -> newRollingWriter(spec, partition));
case PARTITION:
return newRollingWriter(spec, partition);
default:
throw new UnsupportedOperationException("Unsupported delete granularity: " + granularity);
}
}
private RollingPositionDeleteWriter<T> newRollingWriter(
PartitionSpec spec, StructLike partition) {
return new RollingPositionDeleteWriter<>(
writerFactory, fileFactory, io, targetFileSizeInBytes, spec, partition);
}
@Override
protected void addResult(DeleteWriteResult result) {
deleteFiles.addAll(result.deleteFiles());
referencedDataFiles.addAll(result.referencedDataFiles());
}
@Override
protected DeleteWriteResult aggregatedResult() {
return new DeleteWriteResult(deleteFiles, referencedDataFiles);View on GitHub (pinned to 86d9c8fc54)
Solutions
- Pass DeleteGranularity.FILE or DeleteGranularity.PARTITION explicitly when constructing the writer.
- Validate/normalize the granularity from configuration before constructing the writer, defaulting to FILE.
- Align library versions if the granularity constant comes from a newer Iceberg release.
Example fix
// before DeleteGranularity g = confValue; // may be null new ClusteredPositionDeleteWriter<>(factory, g, spec); // after DeleteGranularity g = confValue == null ? DeleteGranularity.FILE : confValue;
Defensive patterns
Strategy: validation
Validate before calling
Preconditions.checkArgument(g == DeleteGranularity.FILE || g == DeleteGranularity.PARTITION, "unsupported granularity");
Type guard
static boolean supported(DeleteGranularity g) { return g == DeleteGranularity.FILE || g == DeleteGranularity.PARTITION; } Try / catch
try {
writer.write(...);
} catch (UnsupportedOperationException e) {
// reconstruct writer with FILE granularity
} Prevention
- Never pass null or unvalidated config values as DeleteGranularity.
- Default unknown granularity values to FILE at config parsing time.
- Keep library versions aligned when using newer enum constants.
When it happens
Trigger: Constructing ClusteredPositionDeleteWriter with a DeleteGranularity other than FILE or PARTITION — typically passing null, or an enum constant introduced in a later version while running with an older writer switch.
Common situations: Custom writer code wiring up a DeleteGranularity from config where the mapping/validation step is missing; version skew between a job config that requests a newer granularity and the library version in the classpath.
Related errors
- Unknown delete file content:
- Delete files are currently not supported in changelog scans
- Unsupported content:
- Cannot read unknown manifest type: %s
- Unsupported file content type: ${file.content()}
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/c3ddde7b18ce859b.
Report an issue: GitHub.