apache/iceberg · error · IllegalArgumentException

Unknown Spark table type:

Error message

Unknown Spark table type: 

What it means

Thrown by SparkCatalog.loadTable(ident, version) when the loaded table is neither a SparkTable nor a SparkChangelogTable, i.e. the catalog produced an unrecognized Table implementation. This indicates an internal invariant violation or a custom table type the catalog adapter does not know how to time-travel.

Source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:215

      } 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
      // but Iceberg uses milliseconds for snapshot timestamps
      long timestampMillis = TimeUnit.MICROSECONDS.toMillis(timestamp);
      long snapshotId = SnapshotUtil.snapshotIdAsOfTime(sparkTable.table(), timestampMillis);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Verify you are using the stock org.apache.iceberg.spark.SparkCatalog, not a custom subclass that returns foreign Table implementations.
  2. Report the table class name in the message — check whether your catalog wrapper is inserting a custom Table implementation.
  3. Upgrade Iceberg; a new wrapper type may have been added upstream and fixed in a later release.
  4. If you own a subclass, override loadTable(ident, version) to handle your table type.
Defensive patterns

Strategy: try-catch

Validate before calling

Table t = catalog.loadTable(ident);
if (!(t instanceof SparkTable) && !(t instanceof SparkChangelogTable)) {
  throw new IllegalStateException("Unsupported table type for time travel: " + t.getClass().getName());
}

Type guard

boolean supportsTimeTravel(org.apache.spark.sql.connector.catalog.Table t) {
  return t instanceof org.apache.iceberg.spark.SparkTable;
}

Try / catch

try {
  return catalog.loadTable(ident, version);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Unknown Spark table type")) {
    throw new UnsupportedOperationException("Time travel unavailable for " + ident, e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling loadTable(ident, version) where loadTable(ident) returns a Table object that is not an instance of SparkTable or SparkChangelogTable — practically only possible with a subclassed/custom SparkCatalog overriding load().

Common situations: Custom SparkCatalog subclasses returning their own Table wrappers; internal bugs after Iceberg upgrades introducing new table wrapper types not yet handled in the instanceof chain.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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