{"record":{"id":"e06218b37eeb9958","repo":"apache/iceberg","slug":"as-of-is-not-supported-for-changelogs","errorCode":null,"errorMessage":"AS OF is not supported for changelogs","messagePattern":"AS OF is not supported for changelogs","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java","lineNumber":211,"sourceCode":"\n      try {\n        return sparkTable.copyWithSnapshotId(Long.parseLong(version));\n      } catch (NumberFormatException e) {\n        SnapshotRef ref = sparkTable.table().refs().get(version);\n        ValidationException.check(\n            ref != null,\n            \"Cannot find matching snapshot ID or reference name for version %s\",\n            version);\n\n        if (ref.isBranch()) {\n          return sparkTable.copyWithBranch(version);\n        } else {\n          return sparkTable.copyWithSnapshotId(ref.snapshotId());\n        }\n      }\n\n    } else if (table instanceof SparkChangelogTable) {\n      throw new UnsupportedOperationException(\"AS OF is not supported for changelogs\");\n\n    } else {\n      throw new IllegalArgumentException(\"Unknown Spark table type: \" + table.getClass().getName());\n    }\n  }\n\n  @Override\n  public Table loadTable(Identifier ident, long timestamp) throws NoSuchTableException {\n    Table table = loadTable(ident);\n\n    if (table instanceof SparkTable) {\n      SparkTable sparkTable = (SparkTable) table;\n\n      Preconditions.checkArgument(\n          sparkTable.snapshotId() == null && sparkTable.branch() == null,\n          \"Cannot do time-travel based on both table identifier and AS OF\");\n\n      // convert the timestamp to milliseconds as Spark passes microseconds","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java#L193-L229","documentation":"SparkCatalog.loadTable(ident, version) supports time travel by version/snapshot, but changelog tables (SparkChangelogTable, used by ICEBERG changelog reads) have no single 'current snapshot' to which AS OF can be pinned. Requesting a versioned load on such a table throws UnsupportedOperationException with 'AS OF is not supported for changelogs'.","triggerScenarios":"Calling loadTable(ident, version) when loadTable(ident) returned a SparkChangelogTable; Spark SQL 'SELECT ... FROM tbl VERSION AS OF v' where tbl is read as a changelog table (e.g. streaming/changelog mode enabled).","commonSituations":"Mixing changelog/streaming reads with time-travel queries; generic SQL templating that always appends VERSION AS OF; upgrading a batch query to changelog mode and inheriting the time-travel clause.","solutions":["Remove the VERSION AS OF / AS OF clause when reading in changelog mode.","Read the table in batch mode (disable changelog mode) if historical snapshot access is required.","Use the underlying Table's snapshots API (SnapshotUtil) directly to reason about history instead of AS OF on the changelog reader.","Split the workflow: time-travel reads via batch SparkCatalog path, changelog reads via the streaming path."],"exampleFix":"// before\nspark.sql(\"SELECT * FROM changelog_tbl VERSION AS OF 1234567890\"); // throws\n\n// after\nspark.sql(\"SELECT * FROM changelog_tbl\"); // changelog read without AS OF\n// or, for time travel:\nspark.read().format(\"iceberg\").option(\"snapshot-id\", \"1234567890\").load(\"db.batch_tbl\");","handlingStrategy":"validation","validationCode":"Table plain = sparkCatalog.loadTable(ident);\nif (plain instanceof org.apache.iceberg.spark.SparkChangelogTable) {\n  throw new IllegalArgumentException(\"Remove VERSION AS OF: changelog tables do not support time travel\");\n}","typeGuard":"boolean supportsTimeTravel = !(sparkCatalog.loadTable(ident) instanceof org.apache.iceberg.spark.SparkChangelogTable);","tryCatchPattern":"try {\n  return sparkCatalog.loadTable(ident, version);\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().contains(\"AS OF\")) { /* strip AS OF clause and read changelog plainly */ }\n  throw e;\n}","preventionTips":["Keep time-travel (VERSION/TIMESTAMP AS OF) clauses out of changelog/streaming queries.","Detect changelog mode in query builders and suppress AS OF generation.","Use snapshot-id read options on batch paths when history is needed.","Document that changelog readers expose a stream, not snapshot-pinned views."],"tags":["spark","time-travel","changelog","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}