apache/iceberg · error · UnsupportedOperationException

Cannot add partition field to non-Iceberg table: $table

Error message

Cannot add partition field to non-Iceberg table: $table

What it means

The AddPartitionFieldExec physical plan node commits an updateSpec().addField(...) only when the resolved table is an Iceberg table (a match on iceberg.table). Any other Table implementation falls into the catch-all case and gets this UnsupportedOperationException, because partition-field evolution is Iceberg-specific.

Solutions

  1. Verify the table lives in an Iceberg catalog: check spark.sql.catalog.<name>=org.apache.iceberg.spark.SparkCatalog and the catalog used in the table name.
  2. Use the fully-qualified name with the Iceberg catalog prefix, e.g. `iceberg_catalog.db.t`.
  3. Confirm the underlying table is actually Iceberg (check metadata location in Hive metastore) — if not, migrate it before adding partition fields.
  4. If you intended plain Spark tables, note ADD PARTITION FIELD is not supported there; use partitioning at write time instead.

Example fix

-- before (plain catalog)
ALTER TABLE spark_catalog.db.t ADD PARTITION FIELD days(ts)
-- after (Iceberg catalog)
ALTER TABLE iceberg_catalog.db.t ADD PARTITION FIELD days(ts)
Defensive patterns

Strategy: type-guard

Validate before calling

// Scala: verify the table resolves through an Iceberg catalog first
val isIceberg = spark.conf.get("spark.sql.catalog.iceberg_catalog")
  .contains("org.apache.iceberg.spark.SparkCatalog")
assert(isIceberg, "ADD PARTITION FIELD requires an Iceberg catalog")

Type guard

// Scala
 table match {
  case t: org.apache.iceberg.spark.SparkTable => // Iceberg path
  case _ => // non-Iceberg: skip or fail fast
}

Try / catch

// Scala
try {
  spark.sql(s"ALTER TABLE $ident ADD PARTITION FIELD days(ts)")
} catch {
  case _: UnsupportedOperationException => log.warn(s"$ident is not an Iceberg table; skipping spec evolution")
}

Prevention

When it happens

Trigger: Running `ALTER TABLE ... ADD PARTITION FIELD ...` against a table whose Spark catalog returns a non-Iceberg Table (e.g. a plain Spark V2 table such as Parquet/ORC/JSON datasources, or a non-Iceberg catalog provider).

Common situations: Pointing at the wrong catalog in a multi-catalog setup (using spark_catalog / built-in catalog instead of the Iceberg catalog), accidentally targeting a Hive or Delta table, or misconfiguring spark.sql.catalog.<name> so the extension plans run but resolution yields a foreign table.

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

Appendix: source

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

    catalog: TableCatalog,
    ident: Identifier,
    transform: Transform,
    name: Option[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
          .updateSpec()
          .addField(name.orNull, Spark3Util.toIcebergTerm(transform))
          .commit()

      case table =>
        throw new UnsupportedOperationException(
          s"Cannot add partition field to non-Iceberg table: $table")
    }

    Nil
  }

  override def simpleString(maxFields: Int): String = {
    s"AddPartitionField ${catalog.name}.${ident.quoted} ${name.map(n => s"$n=").getOrElse("")}${transform.describe}"
  }
}

View on GitHub (pinned to 86d9c8fc54)