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
- Target the Iceberg catalog explicitly in the ALTER TABLE statement
- Confirm the column exists in the Iceberg schema before setting it as an identifier field
- 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
- Target the Iceberg catalog explicitly in DDL
- Validate schema/columns before declaring identifier fields
- Restrict Iceberg-only DDL to Iceberg catalogs
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
- Cannot drop identifier fields in non-Iceberg table: $table
- Cannot drop branch on non-Iceberg table: $table
- Cannot drop identifier fields in non-Iceberg table: $table
- Cannot drop partition field in non-Iceberg table: $table
- Cannot drop tag on non-Iceberg table: $table
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)