apache/iceberg · error · java.lang.UnsupportedOperationException

AS OF is not supported for changelogs

Error message

AS OF is not supported for changelogs

What it means

SparkCatalog.loadTable(ident, version) supports time travel by version/snapshot, but changelog tables (SparkChangelogTable, used by ICEBERG changelog reads) have no single 'current snapshot' to which AS OF can be pinned. Requesting a versioned load on such a table throws UnsupportedOperationException with 'AS OF is not supported for changelogs'.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:211

      try {
        return sparkTable.copyWithSnapshotId(Long.parseLong(version));
      } catch (NumberFormatException e) {
        SnapshotRef ref = sparkTable.table().refs().get(version);
        ValidationException.check(
            ref != null,
            "Cannot find matching snapshot ID or reference name for version %s",
            version);

        if (ref.isBranch()) {
          return sparkTable.copyWithBranch(version);
        } else {
          return sparkTable.copyWithSnapshotId(ref.snapshotId());
        }
      }

    } else if (table instanceof SparkChangelogTable) {
      throw new UnsupportedOperationException("AS OF is not supported for changelogs");

    } else {
      throw new IllegalArgumentException("Unknown Spark table type: " + table.getClass().getName());
    }
  }

  @Override
  public Table loadTable(Identifier ident, long timestamp) throws NoSuchTableException {
    Table table = loadTable(ident);

    if (table instanceof SparkTable) {
      SparkTable sparkTable = (SparkTable) table;

      Preconditions.checkArgument(
          sparkTable.snapshotId() == null && sparkTable.branch() == null,
          "Cannot do time-travel based on both table identifier and AS OF");

      // convert the timestamp to milliseconds as Spark passes microseconds

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Remove the VERSION AS OF / AS OF clause when reading in changelog mode.
  2. Read the table in batch mode (disable changelog mode) if historical snapshot access is required.
  3. Use the underlying Table's snapshots API (SnapshotUtil) directly to reason about history instead of AS OF on the changelog reader.
  4. Split the workflow: time-travel reads via batch SparkCatalog path, changelog reads via the streaming path.

Example fix

// before
spark.sql("SELECT * FROM changelog_tbl VERSION AS OF 1234567890"); // throws

// after
spark.sql("SELECT * FROM changelog_tbl"); // changelog read without AS OF
// or, for time travel:
spark.read().format("iceberg").option("snapshot-id", "1234567890").load("db.batch_tbl");
Defensive patterns

Strategy: validation

Validate before calling

Table plain = sparkCatalog.loadTable(ident);
if (plain instanceof org.apache.iceberg.spark.SparkChangelogTable) {
  throw new IllegalArgumentException("Remove VERSION AS OF: changelog tables do not support time travel");
}

Type guard

boolean supportsTimeTravel = !(sparkCatalog.loadTable(ident) instanceof org.apache.iceberg.spark.SparkChangelogTable);

Try / catch

try {
  return sparkCatalog.loadTable(ident, version);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("AS OF")) { /* strip AS OF clause and read changelog plainly */ }
  throw e;
}

Prevention

When it happens

Trigger: Calling loadTable(ident, version) when loadTable(ident) returned a SparkChangelogTable; Spark SQL 'SELECT ... FROM tbl VERSION AS OF v' where tbl is read as a changelog table (e.g. streaming/changelog mode enabled).

Common situations: Mixing changelog/streaming reads with time-travel queries; generic SQL templating that always appends VERSION AS OF; upgrading a batch query to changelog mode and inheriting the time-travel clause.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/e06218b37eeb9958. Report an issue: GitHub.