apache/iceberg · error · UnsupportedOperationException

Cannot set identifier fields in non-Iceberg table: $table

Error message

Cannot set identifier fields in non-Iceberg table: $table

What it means

SetIdentifierFieldsExec throws this when ALTER TABLE ... SET IDENTIFIER FIELDS is executed against a non-Iceberg table. Identifier fields are declared through Iceberg's UpdateSchema API; other V2 catalogs have no equivalent, so the executor throws UnsupportedOperationException when the table is not a SparkTable wrapping an Iceberg table.

Solutions

  1. Target the Iceberg catalog explicitly in the ALTER TABLE statement
  2. Confirm the column exists in the Iceberg schema before setting it as an identifier field
  3. Remove identifier-field DDL from non-Iceberg pipelines, or migrate the tables to Iceberg

Example fix

// before
ALTER TABLE spark_catalog.default.t SET IDENTIFIER FIELDS id;
// after
ALTER TABLE iceberg_catalog.default.t SET IDENTIFIER FIELDS id;
Defensive patterns

Strategy: validation

Validate before calling

val loaded = catalog.loadTable(ident)
require(loaded.isInstanceOf[org.apache.iceberg.spark.source.SparkTable], s"SET IDENTIFIER FIELDS requires Iceberg: $ident")

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(s"ALTER TABLE $ident SET IDENTIFIER FIELDS id") } catch { case e: UnsupportedOperationException if e.getMessage.contains("non-Iceberg") => throw new IllegalStateException(s"Upsert keys need an Iceberg table: $ident", e) }

Prevention

When it happens

Trigger: Running `ALTER TABLE ... SET IDENTIFIER FIELDS id` where the resolved table comes from a non-Iceberg DataSourceV2 catalog.

Common situations: Upsert-key setup scripts run against Delta tables; wrong catalog prefix; environments where the Iceberg extensions parse the SQL but the table is not 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/fd8d96f37bfe9076. Report an issue: GitHub.

Appendix: source

Thrown at spark/v4.1/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/SetIdentifierFieldsExec.scala:42

import org.apache.spark.sql.connector.catalog.Identifier
import org.apache.spark.sql.connector.catalog.TableCatalog
import scala.jdk.CollectionConverters._

case class SetIdentifierFieldsExec(catalog: TableCatalog, ident: Identifier, fields: Seq[String])
    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 =>
        iceberg.table
          .updateSchema()
          .setIdentifierFields(fields.asJava)
          .commit();
      case table =>
        throw new UnsupportedOperationException(
          s"Cannot set identifier fields in non-Iceberg table: $table")
    }

    Nil
  }

  override def simpleString(maxFields: Int): String = {
    s"SetIdentifierFields ${catalog.name}.${ident.quoted} (${fields.quoted})";
  }
}

View on GitHub (pinned to 86d9c8fc54)