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

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.

Source

Thrown at spark/v4.2/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 (created/registered via an Iceberg catalog) before running branch DDL
  2. Use the fully qualified table name with the correct Iceberg catalog, e.g. ALTER TABLE iceberg_catalog.db.tbl CREATE BRANCH ...
  3. Check spark catalog configuration (spark.sql.catalog.<name> = org.apache.iceberg.spark.SparkCatalog) so the table resolves to Iceberg
  4. If the table is not Iceberg, migrate it to Iceberg first, or use the storage provider's own branching feature instead

Example fix

// before: table in a non-Iceberg catalog
ALTER TABLE my_hive_table CREATE BRANCH audit;
// after: explicitly target the Iceberg catalog
ALTER TABLE iceberg_catalog.db.my_hive_table CREATE BRANCH audit;
Defensive patterns

Strategy: validation

Validate before calling

import org.apache.iceberg.spark.Spark3Util
val icebergTable = Spark3Util.loadIcebergTable(spark, fullTableName)
require(icebergTable != null, s"$fullTableName is not an Iceberg table")

Type guard

def isIcebergTable(spark: SparkSession, name: String): Boolean =
  scala.util.Try(Spark3Util.loadIcebergTable(spark, name)).map(_ != null).getOrElse(false)

Prevention

When it happens

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

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

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