prestodb/presto · error · PrestoException

ICEBERG_INVALID_SNAPSHOT_ID

ICEBERG_INVALID_SNAPSHOT_ID

Error message

Invalid snapshot [%s] for table: %s

What it means

When a table handle carries an explicit snapshot id, getIcebergSystemTable verifies the snapshot actually exists on the loaded Iceberg table via table.snapshot(snapshotId). A null result means the id doesn't correspond to any snapshot of this table (expired, wrong table, or garbage id), and ICEBERG_INVALID_SNAPSHOT_ID is thrown.

Source

Thrown at presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java:1564

                Optional.empty());
    }

    @Override
    public Optional<SystemTable> getSystemTable(ConnectorSession session, SchemaTableName tableName)
    {
        IcebergTableName name = IcebergTableName.from(tableName.getTableName());
        if (name.getTableType() == DATA || name.getTableType() == CHANGELOG) {
            return Optional.empty();
        }
        SchemaTableName icebergTableName = new SchemaTableName(tableName.getSchemaName(), name.getTableName());
        if (!tableExists(session, icebergTableName)) {
            return Optional.empty();
        }

        Table icebergTable = getIcebergTable(session, icebergTableName);

        if (name.getSnapshotId().isPresent() && icebergTable.snapshot(name.getSnapshotId().get()) == null) {
            throw new PrestoException(ICEBERG_INVALID_SNAPSHOT_ID, format("Invalid snapshot [%s] for table: %s", name.getSnapshotId().get(), icebergTable));
        }

        return getIcebergSystemTable(tableName, icebergTable);
    }

    @Override
    public void truncateTable(ConnectorSession session, ConnectorTableHandle tableHandle)
    {
        shouldRunInAutoCommitTransaction("TRUNCATE TABLE");
        IcebergTableHandle handle = (IcebergTableHandle) tableHandle;
        Table icebergTable = getIcebergTable(session, handle.getSchemaTableName());
        removeScanFiles(handle, icebergTable, TupleDomain.all());
    }

    @Override
    public ConnectorDistributedProcedureHandle beginCallDistributedProcedure(
            ConnectorSession session,
            QualifiedObjectName procedureName,

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Run SELECT * FROM iceberg.t".snapshots (or SHOW SNAPSHOTS equivalent) to list valid snapshot ids and pick a current one.
  2. Increase retention / stop expiring the needed snapshot, then retry with its id.
  3. Verify the id belongs to the same table you're querying; correct typos or use FOR TIMESTAMP AS OF with a known timestamp instead.

Example fix

// before
SELECT * FROM iceberg.t FOR VERSION AS OF 123456789; -- expired
// after
SELECT * FROM iceberg.t".snapshots; -- find valid id
SELECT * FROM iceberg.t FOR VERSION AS OF 987654321;
Defensive patterns

Strategy: validation

Validate before calling

Set<Long> validIds = icebergTable.snapshots().stream()
    .map(Snapshot::snapshotId).collect(toSet());
if (!validIds.contains(requestedSnapshotId)) {
    throw new IllegalArgumentException("Snapshot " + requestedSnapshotId + " not on table " + tableName);
}

Try / catch

try {
    return queryForSnapshot(tableName, snapshotId);
} catch (PrestoException e) {
    if (e.getErrorCode().code() == ICEBERG_INVALID_SNAPSHOT_ID) {
        long latest = latestSnapshotId(tableName); // from snapshots system table
        return queryForSnapshot(tableName, latest);
    }
    throw e;
}

Prevention

When it happens

Trigger: Querying iceberg.t FOR VERSION AS OF <id> (or via a system table like snapshots/history with an explicit snapshot) where the id was expired by snapshot expiry/retention, belongs to a different table, or was mistyped.

Common situations: Snapshot ids invalidated by expire_snapshots / retention cleanup; copying a snapshot id between environments or tables; using an id from before a table was dropped and recreated.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/b9a2de0cf3f84309. Report an issue: GitHub.