apache/iceberg · error · IllegalStateException
Cannot find snapshot older than
Error message
Cannot find snapshot older than
What it means
SnapshotUtil.oldestAncestorAfter walks the snapshot ancestry chain looking for the oldest ancestor whose committed timestamp is after the given timestamp. If it exhausts the chain (no snapshot in the lineage is newer than the timestamp and the chain terminates without a null-parent snapshot in range), it throws this IllegalStateException.
Solutions
- Verify the requested timestamp is within the retained snapshot history (check current snapshot's ancestor list first)
- Guard with SnapshotUtil.ancestorIds/table.currentSnapshot() and handle the empty-lineage case before calling
- Lower retention (increase maxSnapshotAgeMs / minSnapshotsToKeep) so old ancestors are not expired
- Catch IllegalStateException and treat as 'no snapshot older than timestamp' for your use case
Example fix
// before Snapshot s = SnapshotUtil.oldestAncestorAfter(table, tsMillis); // after List<Long> ancestors = SnapshotUtil.snapshotIds(table.currentSnapshot(), null); // or ancestorIds Optional-style guard: Snapshot s = ancestors.isEmpty() ? null : SnapshotUtil.oldestAncestorAfter(table, Math.max(tsMillis, firstCommitTs));
Defensive patterns
Strategy: validation
Validate before calling
long oldestTs = SnapshotUtil.oldestAncestorTs != null ? ... : table.currentSnapshot().timestampMillis();
if (tsMillis < SnapshotUtil.ancestorIds(table.currentSnapshot(), null).size() && firstCommitTs > tsMillis) {
// timestamp predates retained history — handle before calling
} Prevention
- Check the timestamp falls within retained snapshot history before calling
- Avoid expiring ancestors that incremental consumers still need
- Convert timestamps to millis consistently
- Catch IllegalStateException as a 'no data that old' signal
When it happens
Trigger: Calling oldestAncestorAfter(table, timestampMillis) with a timestamp older than the table's first snapshot commit, or on a lineage where the ancestor walk cannot find a snapshot older than the timestamp (e.g. expired snapshots removed the chain tail).
Common situations: Incremental/incremental-consumer logic computing changes since a timestamp that predates snapshot expiry (expireSnapshots removed old ancestors); passing millis vs seconds confusion; computing on an empty/new table with a future timestamp.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- Avro does not support LOCAL TIMESTAMP type with precision
- Avro does not support LOCAL TIMESTAMP type with precision…
- Avro does not support TIMESTAMP type with precision
- Avro does not support TIMESTAMP type with precision
- Avro does not support TIMESTAMP type with precision: " +…
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/16a71a5ac22ac6d1.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/util/SnapshotUtil.java:182
}
Snapshot lastSnapshot = null;
for (Snapshot snapshot : currentAncestors(table)) {
if (snapshot.timestampMillis() < timestampMillis) {
return lastSnapshot;
} else if (snapshot.timestampMillis() == timestampMillis) {
return snapshot;
}
lastSnapshot = snapshot;
}
if (lastSnapshot != null && lastSnapshot.parentId() == null) {
// this is the first snapshot in the table, return it
return lastSnapshot;
}
throw new IllegalStateException(
"Cannot find snapshot older than " + DateTimeUtil.formatTimestampMillis(timestampMillis));
}
/**
* Returns list of snapshot ids in the range - (fromSnapshotId, toSnapshotId]
*
* <p>This method assumes that fromSnapshotId is an ancestor of toSnapshotId.
*/
public static List<Long> snapshotIdsBetween(Table table, long fromSnapshotId, long toSnapshotId) {
List<Long> snapshotIds =
Lists.newArrayList(
ancestorIds(
table.snapshot(toSnapshotId),
snapshotId -> snapshotId != fromSnapshotId ? table.snapshot(snapshotId) : null));
return snapshotIds;
}
public static Iterable<Long> ancestorIdsBetween(View on GitHub (pinned to 86d9c8fc54)