apache/iceberg · error · UnsupportedOperationException

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

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.

Source

Thrown at spark/v4.0/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. Target the table via an Iceberg catalog alias (e.g. iceberg_catalog.db.t)
  2. Configure the catalog with spark.sql.catalog.<name>=org.apache.iceberg.spark.SparkCatalog
  3. Verify with DESCRIBE TABLE / catalog metadata that the table is an Iceberg table before running branch DDL

Example fix

// before
ALTER TABLE spark_catalog.db.t CREATE OR REPLACE BRANCH audit;
// after
ALTER TABLE iceberg_catalog.db.t CREATE OR REPLACE BRANCH audit;
Defensive patterns

Strategy: try-catch

Validate before calling

val catalogImpl = spark.conf.get(s"spark.sql.catalog.$catalogName")
require(catalogImpl == "org.apache.iceberg.spark.SparkCatalog" || catalogImpl == "org.apache.iceberg.spark.SparkSessionCatalog", "Branch DDL requires an Iceberg catalog")

Type guard

def isIcebergTable(t: Table): Boolean = t.isInstanceOf[IcebergTable]

Try / catch

try { spark.sql(ddl) } catch { case _: UnsupportedOperationException => log.error("CREATE OR REPLACE BRANCH requires an Iceberg table") }

Prevention

When it happens

Trigger: 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.).

Common situations: 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.

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/dfd509d645c9f7c1. Report an issue: GitHub.