apache/iceberg · error

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 UnsupportedOperationException when a SET IDENTIFIER FIELDS statement targets a non-Iceberg table. Setting identifier fields requires Iceberg's updateSchema().setIdentifierFields() API, exposed only by SparkTable instances wrapping Iceberg tables. Any other resolved table reaches the fallback throwing case.

Source

Thrown at spark/v3.5/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)

Solutions

  1. Verify the provider with DESC TABLE EXTENDED and confirm iceberg.
  2. Qualify the statement with the Iceberg catalog: ALTER TABLE iceberg_catalog.db.tbl SET IDENTIFIER FIELDS id.
  3. Register the catalog as org.apache.iceberg.spark.SparkCatalog so identifiers produce SparkTables.
  4. Migrate the table to Iceberg if identifier fields are needed for row-level operations.

Example fix

-- before
ALTER TABLE db.events SET IDENTIFIER FIELDS event_id; -- non-Iceberg
-- after
ALTER TABLE iceberg_catalog.db.events SET IDENTIFIER FIELDS event_id;
Defensive patterns

Strategy: validation

Validate before calling

val provider = spark.sql("DESC TABLE EXTENDED cat.db.tbl").where("col_name = 'Provider'").first().getString(1)
require(provider == "iceberg", "SET IDENTIFIER FIELDS requires Iceberg")

Type guard

def supportsIdentifierFields(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.tbl SET IDENTIFIER FIELDS event_id") } catch { case e: UnsupportedOperationException if e.getMessage.contains("non-Iceberg") => log.warn("identifier fields require an Iceberg table") }

Prevention

When it happens

Trigger: Running ALTER TABLE ... SET IDENTIFIER FIELDS <cols> where the resolved table does not match `iceberg: SparkTable`, so the pattern match fails.

Common situations: Identifier-field DDL executed on Hive/Delta tables; wrong catalog binding so the command resolves through a non-Iceberg provider; teams rolling out row-level-dedupe features onto tables not yet migrated to 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/fd939ccd9f2eb71e. Report an issue: GitHub.