{"record":{"id":"98453e9801a92a6a","repo":"apache/iceberg","slug":"cannot-add-partition-field-to-non-iceberg-table-98453e","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":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.0/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/v4.0/spark-extensions/src/main/scala/org/apache/spark/sql/execution/datasources/v2/AddPartitionFieldExec.scala#L30-L59","documentation":"AddPartitionFieldExec applies `ALTER TABLE ... ADD PARTITION FIELD` only to tables backed by the Iceberg catalog. When the resolved Spark V2 table is not an IcebergTable (any other provider), the executor throws UnsupportedOperationException because updateSpec() is an Iceberg-only API.","triggerScenarios":"Running `ALTER TABLE catalog.db.t ADD PARTITION FIELD bucket(16, id)` where t resolves to a non-Iceberg V2 catalog table (JDBC, Delta via V2, Spark's built-in catalogs, etc.).","commonSituations":"Pointing the statement at the default Spark catalog or a non-Iceberg session catalog; using a catalog alias that maps to the wrong implementation; expecting Iceberg extensions to work generically on any V2 table.","solutions":["Reference the table through an Iceberg catalog, e.g. iceberg_catalog.db.t","Ensure the catalog is configured as an IcebergCatalog (spark.sql.catalog.<name>=org.apache.iceberg.spark.SparkCatalog)","Confirm the table actually exists in the Iceberg catalog rather than being created by another provider"],"exampleFix":"// before\nALTER TABLE spark_catalog.db.t ADD PARTITION FIELD bucket(16, id);\n// after\nALTER TABLE iceberg_catalog.db.t ADD PARTITION FIELD bucket(16, id);","handlingStrategy":"try-catch","validationCode":"val isIceberg = spark.sessionState.catalogManager.currentCatalog.asInstanceOf[SupportsNamespaces]\n  .loadTable(ident).isInstanceOf[IcebergTable]","typeGuard":"def isIcebergTable(t: Table): Boolean = t.isInstanceOf[IcebergTable]","tryCatchPattern":"try { spark.sql(ddl) } catch { case _: UnsupportedOperationException => log.error(\"ADD PARTITION FIELD requires an Iceberg catalog table\") }","preventionTips":["Qualify Iceberg tables with an Iceberg catalog alias in all DDL","Verify catalog configuration (spark.sql.catalog.<name>) points to SparkCatalog","Check table provider with DESCRIBE TABLE EXTENDED before Iceberg-specific DDL"],"tags":["spark","iceberg","partitioning","unsupported-operation"],"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"}