{"record":{"id":"fc7f5d592cdf325d","repo":"apache/iceberg","slug":"cannot-create-or-replace-branch-on-non-iceberg-tab-fc7f5d","errorCode":null,"errorMessage":"Cannot create or replace branch on non-Iceberg table: $table","messagePattern":"Cannot create or replace branch on non-Iceberg table: \\$table","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.2/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/CreateOrReplaceBranchExec.scala","lineNumber":93,"sourceCode":"          safeCreateBranch()\n        }\n\n        if (branchOptions.numSnapshots.nonEmpty) {\n          manageSnapshots.setMinSnapshotsToKeep(branch, branchOptions.numSnapshots.get.toInt)\n        }\n\n        if (branchOptions.snapshotRetain.nonEmpty) {\n          manageSnapshots.setMaxSnapshotAgeMs(branch, branchOptions.snapshotRetain.get)\n        }\n\n        if (branchOptions.snapshotRefRetain.nonEmpty) {\n          manageSnapshots.setMaxRefAgeMs(branch, branchOptions.snapshotRefRetain.get)\n        }\n\n        manageSnapshots.commit()\n\n      case table =>\n        throw new UnsupportedOperationException(\n          s\"Cannot create or replace branch on non-Iceberg table: $table\")\n    }\n\n    Nil\n  }\n\n  override def simpleString(maxFields: Int): String = {\n    s\"CreateOrReplace branch: $branch for table: ${ident.quoted}\"\n  }\n}\n","sourceCodeStart":75,"sourceCodeEnd":104,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.2/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/CreateOrReplaceBranchExec.scala#L75-L104","documentation":"This UnsupportedOperationException is thrown by Spark's CREATE OR REPLACE BRANCH execution when the resolved table is not an Iceberg table (i.e. not an IcebergSparkTable backing a SparkTable V2 catalog entry). Branch management (snapshot references) is an Iceberg-only feature, so the operation only works when the target table can be matched to an Iceberg table. The error surfaces because the SQL command was routed through the Iceberg extensions but the table itself was loaded from a non-Iceberg provider.","triggerScenarios":"Running 'ALTER TABLE ... CREATE OR REPLACE BRANCH ...' (or CREATE BRANCH) against a table that resolves to a non-Iceberg Spark table, e.g. a Delta/Parquet/Hive table, or a table loaded through a generic DataSourceV2 catalog rather than the Iceberg catalog.","commonSituations":"Pointing the SQL at the wrong catalog or table name; a session catalog alias resolving to a non-Iceberg provider; misconfigured catalog registration so the table is not recognized as Iceberg.","solutions":["Verify the target table is an Iceberg table (created/registered via an Iceberg catalog) before running branch DDL","Use the fully qualified table name with the correct Iceberg catalog, e.g. ALTER TABLE iceberg_catalog.db.tbl CREATE BRANCH ...","Check spark catalog configuration (spark.sql.catalog.<name> = org.apache.iceberg.spark.SparkCatalog) so the table resolves to Iceberg","If the table is not Iceberg, migrate it to Iceberg first, or use the storage provider's own branching feature instead"],"exampleFix":"// before: table in a non-Iceberg catalog\nALTER TABLE my_hive_table CREATE BRANCH audit;\n// after: explicitly target the Iceberg catalog\nALTER TABLE iceberg_catalog.db.my_hive_table CREATE BRANCH audit;","handlingStrategy":"validation","validationCode":"import org.apache.iceberg.spark.Spark3Util\nval icebergTable = Spark3Util.loadIcebergTable(spark, fullTableName)\nrequire(icebergTable != null, s\"$fullTableName is not an Iceberg table\")","typeGuard":"def isIcebergTable(spark: SparkSession, name: String): Boolean =\n  scala.util.Try(Spark3Util.loadIcebergTable(spark, name)).map(_ != null).getOrElse(false)","tryCatchPattern":null,"preventionTips":["Always qualify Iceberg DDL with the Iceberg catalog name","Verify spark.sql.catalog.<name>=org.apache.iceberg.spark.SparkCatalog registration","Check the table's provider with DESCRIBE TABLE EXTENDED before branch DDL"],"tags":["spark","iceberg","unsupported-operation","branch"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}