{"record":{"id":"ee4f81e0852cd6cf","repo":"apache/iceberg","slug":"cannot-delete-map-keys","errorCode":null,"errorMessage":"Cannot delete map keys: ","messagePattern":"Cannot delete map keys: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/SchemaUpdate.java","lineNumber":718,"sourceCode":"          elementUpdate != null ? elementUpdate.isOptional() : list.isElementOptional();\n\n      if (isElementOptional == elementField.isOptional() && list.elementType() == elementType) {\n        return list;\n      }\n\n      if (isElementOptional) {\n        return Types.ListType.ofOptional(list.elementId(), elementType);\n      } else {\n        return Types.ListType.ofRequired(list.elementId(), elementType);\n      }\n    }\n\n    @Override\n    public Type map(Types.MapType map, Type kResult, Type valueResult) {\n      // if any updates are intended for the key, throw an exception\n      int keyId = map.fields().get(0).fieldId();\n      if (deletes.contains(keyId)) {\n        throw new IllegalArgumentException(\"Cannot delete map keys: \" + map);\n      } else if (updates.containsKey(keyId)) {\n        throw new IllegalArgumentException(\"Cannot update map keys: \" + map);\n      } else if (parentToAddedIds.containsKey(keyId)) {\n        throw new IllegalArgumentException(\"Cannot add fields to map keys: \" + map);\n      } else if (!map.keyType().equals(kResult)) {\n        throw new IllegalArgumentException(\"Cannot alter map keys: \" + map);\n      }\n\n      // use field to apply updates to the value\n      Types.NestedField valueField = map.fields().get(1);\n      Type valueType = field(valueField, valueResult);\n      if (valueType == null) {\n        throw new IllegalArgumentException(\"Cannot delete value type from map: \" + map);\n      }\n\n      Types.NestedField valueUpdate = updates.get(valueField.fieldId());\n      boolean isValueOptional =\n          valueUpdate != null ? valueUpdate.isOptional() : map.isValueOptional();","sourceCodeStart":700,"sourceCodeEnd":736,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/SchemaUpdate.java#L700-L736","documentation":"Iceberg map types store keys as a hidden nested field, and the schema evolution spec forbids any change to map keys because keys are part of the data's identity/partitioning semantics. When SchemaUpdate.apply detects that the map's key field ID appears in the deletes set, it throws this IllegalArgumentException rather than producing an invalid updated schema.","triggerScenarios":"Calling updateSchema.delete(keyFieldId) where keyFieldId is the internal field ID of a map's key (map.fields().get(0).fieldId()).","commonSituations":"Generic schema-cleanup tooling iterating over all nested field IDs (including implicit map key/value IDs) and deleting them; users misreading the map key's field ID from Schema.description/ids and targeting it for removal.","solutions":["Do not delete map keys; instead delete the whole map column by its top-level field ID","Restrict delete operations to fields surfaced as user-manageable (top-level columns and struct fields)"],"exampleFix":"// before\nupdateSchema.delete(mapType.fields().get(0).fieldId()); // key id — throws\n// after\nupdateSchema.delete(mapColumn.fieldId()); // delete the map column instead","handlingStrategy":"validation","validationCode":"Types.MapType map = ...;\nint keyId = map.fields().get(0).fieldId();\nif (requestedDeletes.contains(keyId)) throw new IllegalArgumentException(\"Map keys cannot be deleted; delete the map column \" + mapColumnId + \" instead\");","typeGuard":"static boolean isMapKeyId(Types.NestedField mapColumn) {\n  return mapColumn.type() instanceof Types.MapType && mapColumn.type().asMapType().fields().get(0).fieldId() != mapColumn.fieldId();\n}\n// guard: requestedDeleteId != mapType.asMapType().keyId()","tryCatchPattern":"try {\n  updateSchema.apply();\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().equals(\"Cannot delete map keys: \" + e.getMessage().substring(\"Cannot delete map keys: \".length()))) { /* always rebuild message check */ }\n  if (e.getMessage().startsWith(\"Cannot delete map keys\")) throw new IllegalStateException(\"Drop and re-add the map column instead\", e);\n  throw e;\n}","preventionTips":["Never target map key field IDs with delete operations","Only expose top-level columns and struct children as deletable in tooling UIs","Remember map keys are identity-bearing and immutable by spec"],"tags":["schema","schema-evolution","validation"],"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"}