{"record":{"id":"04dbd1645c4369d2","repo":"apache/iceberg","slug":"cannot-add-fields-to-map-keys","errorCode":null,"errorMessage":"Cannot add fields to map keys: ","messagePattern":"Cannot add fields to map keys: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/SchemaUpdate.java","lineNumber":722,"sourceCode":"      }\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();\n\n      if (isValueOptional == map.isValueOptional() && map.valueType() == valueType) {\n        return map;\n      }","sourceCodeStart":704,"sourceCodeEnd":740,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/SchemaUpdate.java#L704-L740","documentation":"Map key fields cannot have child fields added — keys must be primitive types, and the hidden key field is not a valid parent for new nested fields. If SchemaUpdate.apply sees the map key's field ID in parentToAddedIds (i.e. some update attempted to add a field under the key), it throws this IllegalArgumentException.","triggerScenarios":"Calling updateSchema.addColumn(keyFieldId, name, type) or move operations targeting the map key field ID as a parent, or generic tooling that treats every nested field ID as an addable parent.","commonSituations":"Automation that collects all struct-like field IDs as candidate parents and mistakenly includes map key IDs; misunderstanding the hidden map key field as a struct.","solutions":["Add fields only under struct-typed parents (top-level schema or nested structs), never under map key/value field IDs","Filter parent candidates to fields whose type is Types.StructType"],"exampleFix":"// before\nupdateSchema.addColumn(mapKeyFieldId, \"extra\", Types.StringType.get()); // throws\n// after\nupdateSchema.addColumn(null, \"meta\", Types.StructType.of(...)); // add sibling struct field instead","handlingStrategy":"validation","validationCode":"Types.MapType map = ...;\nint keyId = map.fields().get(0).fieldId();\nif (Objects.equals(parentFieldId, keyId)) throw new IllegalArgumentException(\"Cannot add child fields to a map key; keys must be primitive\");","typeGuard":"static boolean isStructParent(Schema schema, int parentFieldId) {\n  Types.NestedField f = schema.findField(parentFieldId) != null ? schema.findField(parentFieldId) : findNested(schema, parentFieldId);\n  return f != null && f.type() instanceof Types.StructType;\n}","tryCatchPattern":"try {\n  updateSchema.apply();\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Cannot add fields to map keys\")) throw new IllegalStateException(\"Parent field must be a struct, not a map key\", e);\n  throw e;\n}","preventionTips":["Validate parent IDs are struct-typed before addColumn calls","Only offer struct fields as parents in tooling","Remember map key/value fields are hidden implementation details, not namespaces"],"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"}