apache/iceberg · error · UnsupportedOperationException
Cannot clean files incrementally when snapshot IDs are speci
Error message
Cannot clean files incrementally when snapshot IDs are specified
What it means
RemoveSnapshots.validateCleanupCanBeIncremental rejects incremental file cleanup when the expiration was targeted at a specific snapshot ID (expireSnapshotsTo/expireSnapshotsById). Incremental cleanup is only valid for the default timestamp-based expiration of main-ancestry snapshots, so the combination is rejected with UnsupportedOperationException.
Source
Thrown at core/src/main/java/org/apache/iceberg/RemoveSnapshots.java:415
&& !hasNonMainSnapshots(current);
}
LOG.info(
"Cleaning up expired files (local, {})", incrementalCleanup ? "incremental" : "reachable");
FileCleanupStrategy cleanupStrategy =
incrementalCleanup
? new IncrementalFileCleanup(
ops.io(), deleteExecutorService, planExecutorService(), deleteFunc)
: new ReachableFileCleanup(
ops.io(), deleteExecutorService, planExecutorService(), deleteFunc);
cleanupStrategy.cleanFiles(base, current, cleanupLevel);
}
private void validateCleanupCanBeIncremental(TableMetadata current) {
if (specifiedSnapshotId) {
throw new UnsupportedOperationException(
"Cannot clean files incrementally when snapshot IDs are specified");
}
if (hasRemovedNonMainAncestors(base, current)) {
throw new UnsupportedOperationException(
"Cannot incrementally clean files when snapshots outside of main ancestry were removed");
}
if (hasNonMainSnapshots(current)) {
throw new UnsupportedOperationException(
"Cannot incrementally clean files when there are snapshots outside of main");
}
}
private boolean hasRemovedNonMainAncestors(
TableMetadata beforeExpiration, TableMetadata afterExpiration) {
Set<Long> mainAncestors = mainAncestors(beforeExpiration);
for (Snapshot snapshotBeforeExpiration : beforeExpiration.snapshots()) {View on GitHub (pinned to 86d9c8fc54)
Solutions
- Drop the snapshot-ID targeting and use default (timestamp/ancestry-based) expiration if incremental cleanup is desired
- Keep the specified snapshot ID but switch the cleanup level to full (e.g. do not request incremental cleanup; use the full cleanup strategy)
- Split the work: run targeted expiration without incremental cleanup, then a normal expiration with incremental cleanup
Example fix
// before
expireSnapshots(table)
.cleanExpiredFiles(true)
.withIncrementalCleanup()
.expireSnapshotsId(12345L)
.execute();
// after
expireSnapshots(table)
.cleanExpiredFiles(true)
.withIncrementalCleanup()
.execute(); // default ancestry-based expiration, or remove withIncrementalCleanup() if ID targeting is required Defensive patterns
Strategy: validation
Validate before calling
// before enabling incremental cleanup, ensure no snapshot ID was specified
boolean specifiedSnapshotId = /* tracked from expireSnapshotsId/To calls */;
if (specifiedSnapshotId) {
throw new IllegalArgumentException("Incremental cleanup requires default (non-ID-targeted) expiration");
} Try / catch
try {
expireSnapshots(table).withIncrementalCleanup().execute();
} catch (UnsupportedOperationException e) {
// rerun without incremental cleanup or without ID targeting
} Prevention
- Use expireSnapshotsId/To only with full cleanup
- Pick one: targeted expiration OR incremental cleanup
- Document cleanup strategy in job configuration to avoid mixing modes
When it happens
Trigger: Calling expireSnapshots(table).expireSnapshotsId(someId)... (or .expireSnapshotsTo(timestamp) with a specified ID path) while cleanup level is incremental — i.e., cleanExpiredFiles enabled with incremental strategy and specifiedSnapshotId is true.
Common situations: Users combining programmatic per-snapshot expiration APIs with the incremental cleanup option introduced for timestamp-based expiration; configuration defaults enabling incremental cleanup while scripts call expireById.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- cleanExpiredMetadata is not supported
- Failed to close manifest list: %s
- Failed to read manifest file: %s
- Cannot incrementally clean files when snapshots outside of m
- Cannot incrementally clean files when there are snapshots ou
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/00cf333d161e98d4.
Report an issue: GitHub.