apache/iceberg · error · UnsupportedOperationException

does not support time travel

Error message

 does not support time travel

What it means

The timestamp-based loadTable(ident, timestampMicros) overload on SparkRewriteTableCatalog always throws UnsupportedOperationException ('<class> does not support time travel') because rewriting operates on the current table snapshot only.

Source

Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/SparkRewriteTableCatalog.java:66

    String groupId = ident.name();
    Table table = TABLE_CACHE.get(groupId);

    if (table == null) {
      throw new NoSuchTableException(ident);
    }

    return new SparkRewriteTable(table, groupId);
  }

  @Override
  public SparkTable loadTable(Identifier ident, String version) throws NoSuchTableException {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support time travel");
  }

  @Override
  public SparkTable loadTable(Identifier ident, long timestampMicros) throws NoSuchTableException {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support time travel");
  }

  @Override
  public void invalidateTable(Identifier ident) {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support table invalidation");
  }

  @Override
  public SparkTable createTable(Identifier ident, TableInfo tableInfo)
      throws TableAlreadyExistsException {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support creating tables");
  }

  @Override
  public SparkTable alterTable(Identifier ident, TableChange... changes) {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support altering tables");
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Drop timestampAsOf/AS OF clauses when using the rewrite catalog.
  2. Use SparkCatalog for time-travel reads: SELECT ... TIMESTAMP AS OF <ts>.
  3. Keep rewrite operations pointed at the current snapshot only.

Example fix

// before
Table t = rewriteCatalog.loadTable(ident, tsMicros);
// after
Table t = sparkCatalog.loadTable(ident, tsMicros); // timestamp travel via the real catalog
Defensive patterns

Strategy: validation

Validate before calling

if (catalog instanceof SparkRewriteTableCatalog && timestampMicros > 0) {
  throw new IllegalArgumentException("timestampAsOf is not supported by SparkRewriteTableCatalog");
}

Type guard

boolean supportsTimestampTravel(CatalogPlugin c) {
  return !(c instanceof SparkRewriteTableCatalog);
}

Try / catch

try {
  Table t = catalog.loadTable(ident, tsMicros);
} catch (UnsupportedOperationException e) {
  Table t = sparkCatalog.loadTable(ident, tsMicros);
}

Prevention

When it happens

Trigger: Calling loadTable(ident, timestampMicros) on SparkRewriteTableCatalog, or Spark resolving a timestampAsOf/AS OF query against the rewrite catalog.

Common situations: Rewrite procedures with time-travel options; querying historical snapshots through a catalog configured as the rewrite catalog; generic catalog clients using the timestamped overload.

Related errors


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