apache/iceberg · error · UnsupportedOperationException

Delete files are currently not supported in changelog scans

Error message

Delete files are currently not supported in changelog scans

What it means

BaseIncrementalChangelogScan computes a row-level changelog from ancestor snapshots, but snapshots containing delete files (v2 positional/equality deletes) cannot yet produce correct changelog rows. The scan proactively fails with UnsupportedOperationException rather than emitting incomplete changelog data.

Solutions

  1. Avoid delete operations on tables you need changelog scans over, or write changes as data files only
  2. Recreate the table/changelog via rewrite operations that emit data files instead of delete files
  3. Wait for/upgrade to a library version that supports delete files in changelog scans

Example fix

// before
CloseableIterator<ChangelogContent> it = table.createChangelogScan().appendsAfter(startId).iterator();
// after
if (hasDeleteSnapshots(table, startId)) {
  throw new IllegalStateException("Changelog scan unavailable: table snapshots contain delete files");
}
CloseableIterator<ChangelogContent> it = table.createChangelogScan().appendsAfter(startId).iterator();
Defensive patterns

Strategy: try-catch

Validate before calling

boolean hasDeletes = SnapshotUtil.ancestorsBetween(table, toId, fromId).stream()
    .anyMatch(s -> !s.deleteManifests(table.io()).isEmpty());

Try / catch

try (CloseableIterator<...> it = scan.iterator()) { ... } catch (UnsupportedOperationException e) { logger.warn("Changelog unsupported: delete files present"); fallbackToFullScan(); }

Prevention

When it happens

Trigger: table.createChangelogScan().appendsBetween(...)/useSnapshots(...) on a table where any ancestor snapshot between the boundaries has delete manifests — i.e. any MERGE/UPDATE/DELETE producing delete files.

Common situations: v2 format tables using copy-on-write or merge-on-read deletes; users upgrading from append-only workloads to delete workloads and then running changelog scans.

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


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

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/BaseIncrementalChangelogScan.java:109

    return manifestGroup.plan(new CreateDataFileChangeTasks(changelogSnapshots));
  }

  @Override
  public CloseableIterable<ScanTaskGroup<ChangelogScanTask>> planTasks() {
    return TableScanUtil.planTaskGroups(
        planFiles(), targetSplitSize(), splitLookback(), splitOpenFileCost());
  }

  // builds a collection of changelog snapshots (oldest to newest)
  // the order of the snapshots is important as it is used to determine change ordinals
  private Deque<Snapshot> orderedChangelogSnapshots(Long fromIdExcl, long toIdIncl) {
    Deque<Snapshot> changelogSnapshots = new ArrayDeque<>();

    for (Snapshot snapshot : SnapshotUtil.ancestorsBetween(table(), toIdIncl, fromIdExcl)) {
      if (!snapshot.operation().equals(DataOperations.REPLACE)) {
        if (!snapshot.deleteManifests(table().io()).isEmpty()) {
          throw new UnsupportedOperationException(
              "Delete files are currently not supported in changelog scans");
        }

        changelogSnapshots.addFirst(snapshot);
      }
    }

    return changelogSnapshots;
  }

  private Set<Long> toSnapshotIds(Collection<Snapshot> snapshots) {
    return snapshots.stream().map(Snapshot::snapshotId).collect(Collectors.toSet());
  }

  private static Map<Long, Integer> computeSnapshotOrdinals(Deque<Snapshot> snapshots) {
    Map<Long, Integer> snapshotOrdinals = Maps.newHashMap();

    int ordinal = 0;

View on GitHub (pinned to 86d9c8fc54)