apache/iceberg · error · UnsupportedOperationException

Cannot replace partition field in non-Iceberg table: $table

Error message

Cannot replace partition field in non-Iceberg table: $table

What it means

ReplacePartitionFieldExec throws this when ALTER TABLE ... REPLACE PARTITION FIELD targets a non-Iceberg table. Replacing a partition field (removing the old transform and adding a new one via UpdateSpec) is Iceberg partition-evolution functionality; other V2 table implementations do not support it, so the executor throws UnsupportedOperationException.

Solutions

  1. Qualify the statement with the Iceberg catalog so it resolves to an Iceberg table
  2. Confirm both the from and to transforms are valid Iceberg terms (Spark3Util.toIcebergTerm must translate them)
  3. For non-Iceberg tables, use that engine's partition-management features or migrate to Iceberg

Example fix

// before
ALTER TABLE delta_t REPLACE PARTITION FIELD days(ts) WITH month(ts);
// after
ALTER TABLE iceberg_catalog.db.t REPLACE PARTITION FIELD days(ts) WITH month(ts);
Defensive patterns

Strategy: validation

Validate before calling

val loaded = catalog.loadTable(ident)
require(loaded.isInstanceOf[org.apache.iceberg.spark.source.SparkTable], s"REPLACE PARTITION FIELD 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 REPLACE PARTITION FIELD days(ts) WITH month(ts)") } catch { case e: UnsupportedOperationException if e.getMessage.contains("non-Iceberg") => log.error(s"Partition evolution unsupported on $ident") }

Prevention

When it happens

Trigger: Running `ALTER TABLE ... REPLACE PARTITION FIELD days(ts) WITH month(ts)` where the table resolves through a non-Iceberg catalog and the `iceberg: SparkTable` match fails.

Common situations: Partition-granularity change scripts applied to Delta/Hive tables; wrong catalog binding in multi-catalog sessions; migrating pipelines between table formats.

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

Appendix: source

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

          case IdentityTransform(FieldReference(parts))
              if parts.size == 1 && schema.findField(parts.head) == null =>
            // the name is not present in the Iceberg schema, so it must be a partition field name, not a column name
            iceberg.table
              .updateSpec()
              .removeField(parts.head)
              .addField(name.orNull, Spark3Util.toIcebergTerm(transformTo))
              .commit()

          case _ =>
            iceberg.table
              .updateSpec()
              .removeField(Spark3Util.toIcebergTerm(transformFrom))
              .addField(name.orNull, Spark3Util.toIcebergTerm(transformTo))
              .commit()
        }

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

    Nil
  }

  override def simpleString(maxFields: Int): String = {
    s"ReplacePartitionField ${catalog.name}.${ident.quoted} ${transformFrom.describe} " +
      s"with ${name.map(n => s"$n=").getOrElse("")}${transformTo.describe}"
  }
}

View on GitHub (pinned to 86d9c8fc54)