apache/iceberg · error

Cannot create or replace branch on non-Iceberg table: $table

Error message

Cannot create or replace branch on non-Iceberg table: $table

What it means

This UnsupportedOperationException is thrown by CreateOrReplaceBranchExec when a CREATE OR REPLACE BRANCH SQL command targets a table that is not an Iceberg table. The Spark V2 catalog resolved the identifier, but the underlying SparkTable does not wrap an Iceberg table that supports snapshot management, so only SparkTable instances exposing manageSnapshots can execute the plan. It indicates the target table's provider does not support Iceberg branch operations.

Source

Thrown at spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/CreateOrReplaceBranchExec.scala:93

          safeCreateBranch()
        }

        if (branchOptions.numSnapshots.nonEmpty) {
          manageSnapshots.setMinSnapshotsToKeep(branch, branchOptions.numSnapshots.get.toInt)
        }

        if (branchOptions.snapshotRetain.nonEmpty) {
          manageSnapshots.setMaxSnapshotAgeMs(branch, branchOptions.snapshotRetain.get)
        }

        if (branchOptions.snapshotRefRetain.nonEmpty) {
          manageSnapshots.setMaxRefAgeMs(branch, branchOptions.snapshotRefRetain.get)
        }

        manageSnapshots.commit()

      case table =>
        throw new UnsupportedOperationException(
          s"Cannot create or replace branch on non-Iceberg table: $table")
    }

    Nil
  }

  override def simpleString(maxFields: Int): String = {
    s"CreateOrReplace branch: $branch for table: ${ident.quoted}"
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Verify the target table is an Iceberg table: DESC TABLE EXTENDED <table> and check the Provider is 'iceberg'.
  2. Run the command against the correct catalog: USE <iceberg_catalog> or fully qualify catalog.table in the DDL.
  3. Register the Iceberg catalog in Spark conf (spark.sql.catalog.<name>=org.apache.iceberg.spark.SparkCatalog) and re-run the statement.
  4. If you need branches, migrate the data into an Iceberg table first.

Example fix

-- before
CREATE OR REPLACE BRANCH audit_branch IN prod_db.events; -- events is a Delta table
-- after
CREATE OR REPLACE BRANCH audit_branch IN iceberg_catalog.prod_db.events;
Defensive patterns

Strategy: validation

Validate before calling

val provider = spark.table("catalog.db.tbl").queryExecution.logical.collect { case t: org.apache.spark.sql.catalyst.catalog.CatalogTable => t.provider }.headOption
if (!provider.contains("iceberg")) throw new IllegalStateException("target is not an Iceberg table")

Type guard

def isIcebergTable(table: org.apache.spark.sql.connector.catalog.Table): Boolean = table.isInstanceOf[org.apache.iceberg.spark.source.SparkTable]

Try / catch

try { spark.sql("CREATE OR REPLACE BRANCH b IN cat.db.tbl") } catch { case e: UnsupportedOperationException if e.getMessage.contains("non-Iceberg table") => log.warn(s"target not Iceberg: ${e.getMessage}") }

Prevention

When it happens

Trigger: Running CREATE OR REPLACE BRANCH <name> (with optional RETAIN clauses) against a table whose provider is not Iceberg, or against a session catalog whose table does not match `iceberg: SparkTable` in the plan's pattern match.

Common situations: Pointing the branch DDL at a Delta/Parquet/Hive table by mistake; forgetting to USE a catalog registered with SparkCatalog that would produce a SparkTable; using a fallback catalog that resolves to a non-Iceberg V2 table.

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/a4e5afc61636a349. Report an issue: GitHub.