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

  1. Pass DeleteGranularity.FILE or DeleteGranularity.PARTITION explicitly when constructing the writer.
  2. Validate/normalize the granularity from configuration before constructing the writer, defaulting to FILE.
  3. 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

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/c3ddde7b18ce859b. Report an issue: GitHub.