{"record":{"id":"59c9a95c3466bd8c","repo":"apache/iceberg","slug":"cannot-add-duplicate-partition-field-name-s","errorCode":null,"errorMessage":"Cannot add duplicate partition field name: %s","messagePattern":"Cannot add duplicate partition field name: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/BaseUpdatePartitionSpec.java","lineNumber":229,"sourceCode":"    PartitionField newField = recycleOrCreatePartitionField(sourceTransform, name);\n    if (newField.name() == null) {\n      String partitionName =\n          PartitionSpecVisitor.visit(schema, newField, PartitionNameGenerator.INSTANCE);\n      newField =\n          new PartitionField(\n              newField.sourceId(), newField.fieldId(), partitionName, newField.transform());\n    }\n\n    checkForRedundantAddedPartitions(newField);\n    transformToAddedField.put(validationKey, newField);\n\n    PartitionField existingField = nameToField.get(newField.name());\n    if (existingField != null && !deletes.contains(existingField.fieldId())) {\n      if (isVoidTransform(existingField)) {\n        // rename the old deleted field that is being replaced by the new field\n        renameField(existingField.name(), existingField.name() + \"_\" + existingField.fieldId());\n      } else {\n        throw new IllegalArgumentException(\n            String.format(\"Cannot add duplicate partition field name: %s\", name));\n      }\n    } else if (existingField != null && deletes.contains(existingField.fieldId())) {\n      renames.put(existingField.name(), existingField.name() + \"_\" + existingField.fieldId());\n    }\n\n    nameToAddedField.put(newField.name(), newField);\n\n    adds.add(newField);\n\n    return this;\n  }\n\n  @Override\n  public BaseUpdatePartitionSpec removeField(String name) {\n    PartitionField alreadyAdded = nameToAddedField.get(name);\n    Preconditions.checkArgument(\n        alreadyAdded == null, \"Cannot delete newly added field: %s\", alreadyAdded);","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/BaseUpdatePartitionSpec.java#L211-L247","documentation":"When adding a partition field via BaseUpdatePartitionSpec.addField, the resulting field name must be unique among live spec fields. If an existing field (not marked for deletion in this update) already uses the name and is not a void transform eligible for auto-rename, the update throws IllegalArgumentException to prevent ambiguous partition field names.","triggerScenarios":"addField(\"days(ts)\", ...) when a live field named days(ts) already exists and was not removed in the same update; re-adding a deleted field's name without the void-transform rename path applying.","commonSituations":"Migrating specs where a field was dropped and re-added in separate transactions; two engineers independently adding the same partition field; automated schema-evolution jobs replaying duplicate addField calls.","solutions":["Remove the existing field (removeField) in the same update before adding the new one, or pick a distinct name","Check current spec field names before calling addField","If the old field is a void transform, the add will auto-rename it — verify that rename is acceptable"],"exampleFix":"// before\nspecUpdate.addField(\"days(ts)\", Transforms.day(tsType)); // name already exists\n// after\nif (table.spec().fields().stream().noneMatch(f -> f.name().equals(\"days_ts_v2\"))) {\n  specUpdate.addField(\"days_ts_v2\", Transforms.day(tsType));\n}","handlingStrategy":"validation","validationCode":"Set<String> names = table.spec().fields().stream().map(PartitionField::name).collect(Collectors.toSet());\nif (names.contains(newName)) { throw new IllegalArgumentException(\"duplicate partition field: \" + newName); }","typeGuard":null,"tryCatchPattern":"catch (IllegalArgumentException e) { /* use a unique field name or skip the add */ }","preventionTips":["Always inspect table.spec() field names before addField","Use deterministic, suffixed names when re-adding previously removed fields","Make automated spec-evolution jobs idempotent (skip if field already present)"],"tags":["illegal-argument","partition-spec","duplicate-name"],"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"}