apache/iceberg · error · UnsupportedOperationException
Cannot drop branch on non-Iceberg table: $table
Error message
Cannot drop branch on non-Iceberg table: $table
What it means
This error is thrown by DropBranchExec when the ALTER TABLE ... DROP BRANCH command targets a table resolved through a Spark catalog that is not an Iceberg SparkTable. Iceberg branches only exist on Iceberg tables, so the extensions executor unwraps the DataSourceV2 table and throws UnsupportedOperationException for any other table implementation. The operation is fundamentally unsupported outside Iceberg's snapshot reference model.
Solutions
- Verify the table is an Iceberg table (check the catalog it resolves through) before issuing DROP BRANCH
- Qualify the statement with the correct Iceberg catalog: ALTER TABLE iceberg_catalog.db.table DROP BRANCH b1
- If the table is not Iceberg, remove branch-management statements from scripts targeting it, or migrate the table to Iceberg
- Add `IF EXISTS` does not help here — it only suppresses a missing branch, not a non-Iceberg table; fix the target table instead
Example fix
// before ALTER TABLE delta_catalog.db.events DROP BRANCH audit; // after ALTER TABLE iceberg_catalog.db.events DROP BRANCH audit;
Defensive patterns
Strategy: validation
Validate before calling
import org.apache.iceberg.spark.Spark3Util
val catalogAndIdent = Spark3Util.catalogAndIdentifier(spark, "catalog.db.table")
val isIceberg = spark.sessionState.catalogManager
.catalog(catalogAndIdent.catalog()).asInstanceOf[org.apache.spark.sql.connector.catalog.TableCatalog]
.loadTable(catalogAndIdent.identifier()).isInstanceOf[org.apache.iceberg.spark.source.SparkTable]
if (!isIceberg) throw new IllegalStateException("Target table is not an Iceberg table; branch ops unavailable") Type guard
def isIcebergTable(t: org.apache.spark.sql.connector.catalog.Table): Boolean = t.isInstanceOf[org.apache.iceberg.spark.source.SparkTable]
Try / catch
try { spark.sql("ALTER TABLE cat.db.t DROP BRANCH b1") } catch { case e: UnsupportedOperationException if e.getMessage.contains("non-Iceberg table") => log.warn(s"Not an Iceberg table, skipping branch drop: ${e.getMessage}") } Prevention
- Always qualify Iceberg DDL with the Iceberg catalog name
- Check the table's provider/format before running Iceberg-specific SQL
- Keep one catalog convention per environment to avoid mixed-format targets
When it happens
Trigger: Running `ALTER TABLE ... DROP BRANCH <branch>` where the table is registered via a non-Iceberg DataSourceV2 catalog (e.g. Delta, JDBC, or a custom V2 catalog), so the pattern match on `iceberg: SparkTable` falls through to the `case table =>` branch.
Common situations: Pointing the SQL at the wrong catalog or table name; migrating a table to another catalog format and then re-running Iceberg branch management SQL; scripts that assume all tables in a session use the Iceberg catalog.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot drop identifier fields in non-Iceberg table: $table
- Cannot drop partition field in non-Iceberg table: $table
- Cannot drop tag on non-Iceberg table: $table
- Cannot replace partition field in non-Iceberg table: $table
- Cannot set identifier fields in non-Iceberg table: $table
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/f5f329f4f0f47e76.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.1/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/DropBranchExec.scala:47
ident: Identifier,
branch: String,
ifExists: Boolean)
extends LeafV2CommandExec {
import org.apache.spark.sql.connector.catalog.CatalogV2Implicits._
override lazy val output: Seq[Attribute] = Nil
override protected def run(): Seq[InternalRow] = {
catalog.loadTable(ident) match {
case iceberg: SparkTable =>
val ref = iceberg.table().refs().get(branch)
if (ref != null || !ifExists) {
iceberg.table().manageSnapshots().removeBranch(branch).commit()
}
case table =>
throw new UnsupportedOperationException(s"Cannot drop branch on non-Iceberg table: $table")
}
Nil
}
override def simpleString(maxFields: Int): String = {
s"DropBranch branch: ${branch} for table: ${ident.quoted}"
}
}
View on GitHub (pinned to 86d9c8fc54)