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
- Upgrade the Iceberg Spark connector to match your Spark version so all TimeTravel variants are handled
- Use standard VERSION AS OF or TIMESTAMP AS OF syntax, which map to AsOfVersion/AsOfTimestamp
- Avoid custom time-travel specs with the Iceberg catalog
- 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
- Use VERSION AS OF / TIMESTAMP AS OF syntax only
- Keep the Iceberg connector version matched to Spark
- Avoid custom TimeTravel implementations with the Iceberg catalog
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
- AS OF is not supported for changelogs
- Unknown Spark table type:
- Cannot pass path based identifier to %s method. %s is a path
- Unsupported changelog scan task type:
- Unsupported command: ${command}
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/55481d6d21fa4177.
Report an issue: GitHub.