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

  1. Check SnapshotUtil.isAncestorOf(table, snapshotId) before calling snapshotAfter
  2. Refresh the table and confirm the bookmarked snapshot id is still in current lineage; if not, rescan from the current snapshot
  3. Catch IllegalStateException and reset the consumer's bookmark to the current snapshot
  4. 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

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


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)