apache/iceberg · error · IllegalStateException
Cannot find snapshot after
Error message
Cannot find snapshot after %s: not an ancestor of table's current snapshot
What it means
SnapshotUtil.snapshotAfter returns the snapshot that is the direct child of the given snapshotId along the current table ancestry. If snapshotId is not an ancestor of the table's current snapshot (so no child of it exists in the current lineage), it throws this IllegalStateException with the offending id.
Solutions
- Check SnapshotUtil.isAncestorOf(table, snapshotId) before calling snapshotAfter
- Refresh the table and confirm the bookmarked snapshot id is still in current lineage; if not, rescan from the current snapshot
- Catch IllegalStateException and reset the consumer's bookmark to the current snapshot
- Avoid bookmarking staged/cherry-pick snapshot ids; only persist ids from the published main lineage
Example fix
// before
Snapshot next = SnapshotUtil.snapshotAfter(table, bookmarkId);
// after
if (!SnapshotUtil.isAncestorOf(table, bookmarkId)) {
bookmarkId = table.currentSnapshot().snapshotId(); // reset bookmark
}
Snapshot next = SnapshotUtil.snapshotAfter(table, bookmarkId); Defensive patterns
Strategy: validation
Validate before calling
boolean inLineage = SnapshotUtil.isAncestorOf(table, snapshotId);
if (!inLineage) {
snapshotId = table.currentSnapshot().snapshotId(); // reset bookmark
} Try / catch
try {
Snapshot next = SnapshotUtil.snapshotAfter(table, bookmarkId);
} catch (IllegalStateException e) {
bookmarkId = table.refresh().currentSnapshot().snapshotId();
next = null; // rescan
} Prevention
- Verify isAncestorOf before bookmark advancement
- Handle rollback/expiry invalidating bookmarks in consumers
- Only persist ids from the main published lineage
- Refresh table metadata before lineage checks
When it happens
Trigger: Calling SnapshotUtil.snapshotAfter(table, snapshotId) with an id from a different branch (e.g. a rolled-back or WAP branch), an expired snapshot id, or an id from another table entirely.
Common situations: Incremental consumers bookmarking a snapshot id that was later rolled back (rollbackToSnapshot rewrote the lineage); snapshot expiry removed the ancestor; confusing cherry-picked/staged snapshot ids with mainline ancestor ids.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Cannot find snapshot older than
- DuplicateWAPCommitException(wapId)
- Failed on snapshot while reading manifest list
- Failed to load committed snapshot: omitting sequence number…
- Managing snapshots is not supported by +…
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/e90862d28e0419bf.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/util/SnapshotUtil.java:299
/**
* Traverses the history of the table's current snapshot and finds the snapshot with the given
* snapshot id as its parent.
*
* @return the snapshot for which the given snapshot is the parent
* @throws IllegalArgumentException when the given snapshotId is not found in the table
* @throws IllegalStateException when the given snapshotId is not an ancestor of the current table
* state
*/
public static Snapshot snapshotAfter(Table table, long snapshotId) {
Preconditions.checkArgument(
table.snapshot(snapshotId) != null, "Cannot find parent snapshot: %s", snapshotId);
for (Snapshot current : currentAncestors(table)) {
if (current.parentId() == snapshotId) {
return current;
}
}
throw new IllegalStateException(
String.format(
"Cannot find snapshot after %s: not an ancestor of table's current snapshot",
snapshotId));
}
/**
* Returns the ID of the most recent snapshot for the table as of the timestamp.
*
* @param table a {@link Table}
* @param timestampMillis the timestamp in millis since the Unix epoch
* @return the snapshot ID
* @throws IllegalArgumentException when no snapshot is found in the table older than the
* timestamp
*/
public static long snapshotIdAsOfTime(Table table, long timestampMillis) {
Long snapshotId = nullableSnapshotIdAsOfTime(table, timestampMillis);
Preconditions.checkArgument(View on GitHub (pinned to 86d9c8fc54)