{"record":{"id":"11812ebb7d408229","repo":"apache/iceberg","slug":"cannot-specify-the-identifier-fields-because-it-11812e","errorCode":null,"errorMessage":"Cannot specify the 'identifier-fields' because it's a reserved table property. Please use the command 'ALTER TABLE ... SET IDENTIFIER FIELDS' to specify identifier fields.","messagePattern":"Cannot specify the 'identifier-fields' because it's a reserved table property\\. Please use the command 'ALTER TABLE \\.\\.\\. SET IDENTIFIER FIELDS' to specify identifier fields\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java","lineNumber":325,"sourceCode":"    SetProperty pickSnapshotId = null;\n    List<TableChange> propertyChanges = Lists.newArrayList();\n    List<TableChange> schemaChanges = Lists.newArrayList();\n\n    for (TableChange change : changes) {\n      if (change instanceof SetProperty) {\n        SetProperty set = (SetProperty) change;\n        if (TableCatalog.PROP_LOCATION.equalsIgnoreCase(set.property())) {\n          setLocation = set;\n        } else if (\"current-snapshot-id\".equalsIgnoreCase(set.property())) {\n          setSnapshotId = set;\n        } else if (\"cherry-pick-snapshot-id\".equalsIgnoreCase(set.property())) {\n          pickSnapshotId = set;\n        } else if (\"sort-order\".equalsIgnoreCase(set.property())) {\n          throw new UnsupportedOperationException(\n              \"Cannot specify the 'sort-order' because it's a reserved table \"\n                  + \"property. Please use the command 'ALTER TABLE ... WRITE ORDERED BY' to specify write sort-orders.\");\n        } else if (\"identifier-fields\".equalsIgnoreCase(set.property())) {\n          throw new UnsupportedOperationException(\n              \"Cannot specify the 'identifier-fields' because it's a reserved table property. \"\n                  + \"Please use the command 'ALTER TABLE ... SET IDENTIFIER FIELDS' to specify identifier fields.\");\n        } else {\n          propertyChanges.add(set);\n        }\n      } else if (change instanceof RemoveProperty) {\n        propertyChanges.add(change);\n      } else if (change instanceof ColumnChange) {\n        schemaChanges.add(change);\n      } else {\n        throw new UnsupportedOperationException(\"Cannot apply unknown table change: \" + change);\n      }\n    }\n\n    try {\n      org.apache.iceberg.Table table = icebergCatalog.loadTable(buildIdentifier(ident));\n      commitChanges(\n          table, setLocation, setSnapshotId, pickSnapshotId, propertyChanges, schemaChanges);","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java#L307-L343","documentation":"'identifier-fields' is a reserved Iceberg table property that can only be changed through the dedicated SQL syntax ALTER TABLE ... SET IDENTIFIER FIELDS. SparkCatalog.alterTable detects a SetProperty change on this property and throws UnsupportedOperationException to prevent corrupting identifier metadata.","triggerScenarios":"Running ALTER TABLE ... SET TBLPROPERTIES ('identifier-fields'='id') or otherwise submitting an UpdateTable change with property 'identifier-fields' through SparkCatalog.alterTable.","commonSituations":"Scripts replaying a table's full property map (including reserved keys) onto a new table; users manually trying to set identifier fields without knowing the dedicated SQL command; version migrations where identifier fields were configured differently.","solutions":["Use ALTER TABLE ... SET IDENTIFIER FIELDS id (comma-separated for multiple fields) instead of setting the property","Filter reserved keys out of property-copy automation before calling SET TBLPROPERTIES","Use the Iceberg API Table.updateSchema().setIdentifierFields(...) when not using SQL"],"exampleFix":"// before\nALTER TABLE t SET TBLPROPERTIES ('identifier-fields'='id');\n// after\nALTER TABLE t SET IDENTIFIER FIELDS id;","handlingStrategy":"validation","validationCode":"if (\"identifier-fields\".equalsIgnoreCase(key)) { throw new IllegalArgumentException(\"Use ALTER TABLE ... SET IDENTIFIER FIELDS\"); }","typeGuard":"boolean isReservedIcebergProperty(String key) { return Set.of(\"sort-order\",\"identifier-fields\").contains(key.toLowerCase(Locale.ROOT)); }","tryCatchPattern":"try { spark.sql(alterStmt); } catch (UnsupportedOperationException e) { if (e.getMessage().contains(\"identifier-fields\")) { spark.sql(\"ALTER TABLE t SET IDENTIFIER FIELDS \" + fields); } }","preventionTips":["Strip reserved properties before programmatic SET TBLPROPERTIES","Document identifier-fields as API-managed, not property-managed","Use UpdateSchema.setIdentifierFields for programmatic changes"],"tags":["spark","reserved-property","identifier-fields"],"backgroundTag":"invalid-argument-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}