apache/iceberg · error · IllegalArgumentException

Unknown time travel: " + timeTravel

Error message

Unknown time travel: " + timeTravel

What it means

SparkTable.create resolves time travel specifications from Spark's TIME TRAVEL spec; it supports no time travel, AsOfVersion, and AsOfTimestamp. Any other TimeTravel spec instance is rejected with IllegalArgumentException, meaning Spark produced a time travel expression Iceberg does not recognize.

Solutions

  1. Use the supported syntax: `VERSION AS OF` / `TIMESTAMP AS OF` (or `FOR VERSION AS OF` / `FOR TIMESTAMP AS OF`).
  2. Check Spark and Iceberg versions are compatible (spark/v4.1 module expects Spark 4.1).
  3. Pass a plain table or an AsOfVersion/AsOfTimestamp when calling SparkTable.create programmatically.
  4. Upgrade Iceberg if the Spark version introduced new TimeTravel variants.

Example fix

// before
spark.read.option("as-of", something).table("db.tbl")
// after
spark.read.table("db.tbl").option("version-as-of", "1234567890")  // or
spark.sql("SELECT * FROM db.tbl VERSION AS OF 1234567890")
Defensive patterns

Strategy: validation

Validate before calling

if (timeTravel != null && !(timeTravel instanceof AsOfVersion) && !(timeTravel instanceof AsOfTimestamp)) { throw new IllegalArgumentException("unsupported time travel: " + timeTravel); }

Type guard

boolean supported = timeTravel == null || timeTravel instanceof AsOfVersion || timeTravel instanceof AsOfTimestamp;

Try / catch

try { return SparkTable.create(table, timeTravel); } catch (IllegalArgumentException e) { throw new AnalysisException("Use VERSION AS OF or TIMESTAMP AS OF", e); }

Prevention

When it happens

Trigger: CREATE TABLE ... AS / DataFrame read with VERSION AS OF or TIMESTAMP AS OF that resolves to an unexpected TimeTravel subtype passed to SparkTable.create(table, timeTravel).

Common situations: Spark version mismatches where new time travel specs exist; custom catalog/planner wrappers producing a non-standard TimeTravel implementation; using snapshot-id-based travel through an unsupported syntax variant.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/source/SparkTable.java:332

  }

  public static SparkTable create(Table table, String branch) {
    ValidationException.check(
        branch == null || SnapshotRef.MAIN_BRANCH.equals(branch) || table.snapshot(branch) != null,
        "Cannot use branch (does not exist): %s",
        branch);
    return new SparkTable(table, branch);
  }

  public static SparkTable create(Table table, TimeTravel timeTravel) {
    if (timeTravel == null) {
      return new SparkTable(table);
    } else if (timeTravel instanceof AsOfVersion asOfVersion) {
      return createWithVersion(table, asOfVersion);
    } else if (timeTravel instanceof AsOfTimestamp asOfTimestamp) {
      return createWithTimestamp(table, asOfTimestamp);
    } else {
      throw new IllegalArgumentException("Unknown time travel: " + timeTravel);
    }
  }

  private static SparkTable createWithVersion(Table table, AsOfVersion timeTravel) {
    if (timeTravel.isSnapshotId()) {
      return new SparkTable(table, Long.parseLong(timeTravel.version()), timeTravel);
    } else {
      SnapshotRef ref = table.refs().get(timeTravel.version());
      Preconditions.checkArgument(
          ref != null,
          "Cannot find matching snapshot ID or reference name for version %s",
          timeTravel.version());
      if (ref.isBranch()) {
        return new SparkTable(table, timeTravel.version());
      } else {
        return new SparkTable(table, ref.snapshotId(), timeTravel);
      }
    }

View on GitHub (pinned to 86d9c8fc54)