{"record":{"id":"dfd509d645c9f7c1","repo":"apache/iceberg","slug":"cannot-create-or-replace-branch-on-non-iceberg-tab-dfd509","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.0/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.0/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/CreateOrReplaceBranchExec.scala#L75-L104","documentation":"CreateOrReplaceBranchExec implements `ALTER TABLE ... CREATE OR REPLACE BRANCH` only for Iceberg tables. When the target table is any other V2 table provider, the executor throws UnsupportedOperationException since WapSnapshot/manageSnapshots branch management is an Iceberg-only capability.","triggerScenarios":"Running `ALTER TABLE catalog.db.t CREATE OR REPLACE BRANCH b ...` where t resolves to a non-Iceberg table (non-Iceberg catalog implementation, spark_catalog table, etc.).","commonSituations":"Using the default spark_catalog or another provider's catalog while running Iceberg branching DDL; misconfigured catalog class; assuming the extension SQL works on any table format.","solutions":["Target the table via an Iceberg catalog alias (e.g. iceberg_catalog.db.t)","Configure the catalog with spark.sql.catalog.<name>=org.apache.iceberg.spark.SparkCatalog","Verify with DESCRIBE TABLE / catalog metadata that the table is an Iceberg table before running branch DDL"],"exampleFix":"// before\nALTER TABLE spark_catalog.db.t CREATE OR REPLACE BRANCH audit;\n// after\nALTER TABLE iceberg_catalog.db.t CREATE OR REPLACE BRANCH audit;","handlingStrategy":"try-catch","validationCode":"val catalogImpl = spark.conf.get(s\"spark.sql.catalog.$catalogName\")\nrequire(catalogImpl == \"org.apache.iceberg.spark.SparkCatalog\" || catalogImpl == \"org.apache.iceberg.spark.SparkSessionCatalog\", \"Branch DDL requires an Iceberg catalog\")","typeGuard":"def isIcebergTable(t: Table): Boolean = t.isInstanceOf[IcebergTable]","tryCatchPattern":"try { spark.sql(ddl) } catch { case _: UnsupportedOperationException => log.error(\"CREATE OR REPLACE BRANCH requires an Iceberg table\") }","preventionTips":["Use an Iceberg catalog alias for branching/branch DDL","Confirm the catalog implementation class in Spark conf","Validate table format before issuing Iceberg ref-management statements"],"tags":["spark","iceberg","branching","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"}