{"record":{"id":"4a4706463738d2e6","repo":"apache/iceberg","slug":"cannot-add-partition-field-to-non-iceberg-table","errorCode":null,"errorMessage":"Cannot add partition field to non-Iceberg table: $table","messagePattern":"Cannot add partition field to non-Iceberg table: \\$table","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/AddPartitionFieldExec.scala","lineNumber":48,"sourceCode":"    catalog: TableCatalog,\n    ident: Identifier,\n    transform: Transform,\n    name: Option[String])\n    extends LeafV2CommandExec {\n  import org.apache.spark.sql.connector.catalog.CatalogV2Implicits._\n\n  override lazy val output: Seq[Attribute] = Nil\n\n  override protected def run(): Seq[InternalRow] = {\n    catalog.loadTable(ident) match {\n      case iceberg: SparkTable =>\n        iceberg.table\n          .updateSpec()\n          .addField(name.orNull, Spark3Util.toIcebergTerm(transform))\n          .commit()\n\n      case table =>\n        throw new UnsupportedOperationException(\n          s\"Cannot add partition field to non-Iceberg table: $table\")\n    }\n\n    Nil\n  }\n\n  override def simpleString(maxFields: Int): String = {\n    s\"AddPartitionField ${catalog.name}.${ident.quoted} ${name.map(n => s\"$n=\").getOrElse(\"\")}${transform.describe}\"\n  }\n}\n","sourceCodeStart":30,"sourceCodeEnd":59,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/AddPartitionFieldExec.scala#L30-L59","documentation":"ADD PARTITION FIELD can only operate on Iceberg tables because spec evolution is an Iceberg feature. When the resolved V2 table is any other catalog implementation (not a valid iceberg.table), an UnsupportedOperationException is thrown listing the offending table.","triggerScenarios":"Running ALTER TABLE ... ADD PARTITION FIELD against a non-Iceberg V2 table (e.g. a Delta or JDBC V2 catalog table) in Spark 3.5 with Iceberg extensions registered.","commonSituations":"Wrong catalog/provider configured for the table; users assuming all V2 tables support Iceberg partition evolution syntax.","solutions":["Migrate the table to Iceberg (e.g. via snapshot/migrate procedures) before altering the partition spec","Target the correct catalog — verify the table identifier points to an Iceberg catalog, not another provider","Use the provider's native partitioning ALTER syntax for non-Iceberg tables"],"exampleFix":"// before\nCALL cat.system.snapshot('mysql_db.orders', 'iceberg_db.orders'); -- wrong catalog / still non-Iceberg table\nALTER TABLE mysql_db.orders ADD PARTITION FIELD bucket(8, order_id);\n// after\nALTER TABLE iceberg_db.orders ADD PARTITION FIELD bucket(8, order_id);","handlingStrategy":"validation","validationCode":"val catalog = spark.sessionState.catalogManager.catalog(\"my_cat\").asInstanceOf[CatalogPlugin]\nval isIceberg = spark.conf.get(s\"spark.sql.catalog.my_cat\") == \"org.apache.iceberg.spark.SparkCatalog\"\nrequire(isIceberg, \"Target catalog is not an Iceberg catalog\")","typeGuard":null,"tryCatchPattern":"try { spark.sql(alterDdl) } catch { case e: UnsupportedOperationException if e.getMessage.contains(\"non-Iceberg\") => log.error(\"migrate the table to Iceberg first\"); throw e }","preventionTips":["Confirm the table's catalog is backed by org.apache.iceberg before using Iceberg DDL extensions","Use DESCRIBE TABLE EXTENDED to check the provider","Migrate foreign tables with the Iceberg snapshot/migrate procedure first"],"tags":["spark","partitioning","iceberg"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}