apache/iceberg · error · IllegalArgumentException

Unknown time travel: ${timeTravel}

Error message

Unknown time travel: ${timeTravel}

What it means

SparkTable.create() maps Spark's timeTravel spec to an Iceberg snapshot: AsOfVersion maps to version/snapshot-id travel, AsOfTimestamp to timestamp travel. Any other TimeTravel subclass triggers IllegalArgumentException('Unknown time travel: ...') because Iceberg cannot interpret it.

Source

Thrown at spark/v4.2/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)

Solutions

  1. Upgrade the Iceberg Spark connector to match your Spark version so all TimeTravel variants are handled
  2. Use standard VERSION AS OF or TIMESTAMP AS OF syntax, which map to AsOfVersion/AsOfTimestamp
  3. Avoid custom time-travel specs with the Iceberg catalog
  4. Check spark-sql syntax; e.g. use 'SELECT * FROM t VERSION AS OF 123' rather than proprietary variants

Example fix

// before
SELECT * FROM tbl FOR VERSION AS OF 'abc'; -- nonstandard spec
// after
SELECT * FROM tbl VERSION AS OF 4695933054711295165; -- AsOfVersion, supported
Defensive patterns

Strategy: validation

Validate before calling

boolean supported = timeTravel instanceof AsOfVersion || timeTravel instanceof AsOfTimestamp; if (!supported) throw new IllegalArgumentException("Time travel spec not supported by Iceberg: " + timeTravel);

Type guard

boolean isSupportedTimeTravel(TimeTravel t) { return t instanceof AsOfVersion || t instanceof AsOfTimestamp; }

Try / catch

try { return SparkTable.create(table, timeTravel); } catch (IllegalArgumentException e) { log.error("Unsupported time travel spec", e); throw e; }

Prevention

When it happens

Trigger: Executing a time travel query where Spark passes a TimeTravel implementation other than AsOfVersion or AsOfTimestamp — usually a newer Spark feature or custom catalog extension's spec.

Common situations: Spark/Iceberg version skew where a new time-travel variant was added in Spark but the bundled Iceberg connector doesn't recognize it; custom CatalogPlugin supplying its own TimeTravel implementation.

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/55481d6d21fa4177. Report an issue: GitHub.