{"record":{"id":"c62a09ed3f1189a9","repo":"apache/iceberg","slug":"unknown-spark-table-type","errorCode":null,"errorMessage":"Unknown Spark table type: ","messagePattern":"Unknown Spark table type: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java","lineNumber":215,"sourceCode":"      } 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\n      // but Iceberg uses milliseconds for snapshot timestamps\n      long timestampMillis = TimeUnit.MICROSECONDS.toMillis(timestamp);\n      long snapshotId = SnapshotUtil.snapshotIdAsOfTime(sparkTable.table(), timestampMillis);","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java#L197-L233","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","solutions":["Verify you are using the stock org.apache.iceberg.spark.SparkCatalog, not a custom subclass that returns foreign Table implementations.","Report the table class name in the message — check whether your catalog wrapper is inserting a custom Table implementation.","Upgrade Iceberg; a new wrapper type may have been added upstream and fixed in a later release.","If you own a subclass, override loadTable(ident, version) to handle your table type."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"Table t = catalog.loadTable(ident);\nif (!(t instanceof SparkTable) && !(t instanceof SparkChangelogTable)) {\n  throw new IllegalStateException(\"Unsupported table type for time travel: \" + t.getClass().getName());\n}","typeGuard":"boolean supportsTimeTravel(org.apache.spark.sql.connector.catalog.Table t) {\n  return t instanceof org.apache.iceberg.spark.SparkTable;\n}","tryCatchPattern":"try {\n  return catalog.loadTable(ident, version);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Unknown Spark table type\")) {\n    throw new UnsupportedOperationException(\"Time travel unavailable for \" + ident, e);\n  }\n  throw e;\n}","preventionTips":["Use the stock SparkCatalog; inspect any subclasses for overridden load() returning foreign Table types.","After Iceberg upgrades, smoke-test time travel on all catalog types in use.","Capture the class name from the message to debug custom wrappers."],"tags":["spark","iceberg","internal-error","time-travel"],"backgroundTag":"internal-invariant-violation","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"}