apache/iceberg · error · IllegalArgumentException
Cannot add fields to map keys:
Error message
Cannot add fields to map keys:
What it means
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.
Source
Thrown at core/src/main/java/org/apache/iceberg/SchemaUpdate.java:722
}
if (isElementOptional) {
return Types.ListType.ofOptional(list.elementId(), elementType);
} else {
return Types.ListType.ofRequired(list.elementId(), elementType);
}
}
@Override
public Type map(Types.MapType map, Type kResult, Type valueResult) {
// if any updates are intended for the key, throw an exception
int keyId = map.fields().get(0).fieldId();
if (deletes.contains(keyId)) {
throw new IllegalArgumentException("Cannot delete map keys: " + map);
} else if (updates.containsKey(keyId)) {
throw new IllegalArgumentException("Cannot update map keys: " + map);
} else if (parentToAddedIds.containsKey(keyId)) {
throw new IllegalArgumentException("Cannot add fields to map keys: " + map);
} else if (!map.keyType().equals(kResult)) {
throw new IllegalArgumentException("Cannot alter map keys: " + map);
}
// use field to apply updates to the value
Types.NestedField valueField = map.fields().get(1);
Type valueType = field(valueField, valueResult);
if (valueType == null) {
throw new IllegalArgumentException("Cannot delete value type from map: " + map);
}
Types.NestedField valueUpdate = updates.get(valueField.fieldId());
boolean isValueOptional =
valueUpdate != null ? valueUpdate.isOptional() : map.isValueOptional();
if (isValueOptional == map.isValueOptional() && map.valueType() == valueType) {
return map;
}View on GitHub (pinned to 86d9c8fc54)
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
Example fix
// before updateSchema.addColumn(mapKeyFieldId, "extra", Types.StringType.get()); // throws // after updateSchema.addColumn(null, "meta", Types.StructType.of(...)); // add sibling struct field instead
Defensive patterns
Strategy: validation
Validate before calling
Types.MapType map = ...;
int keyId = map.fields().get(0).fieldId();
if (Objects.equals(parentFieldId, keyId)) throw new IllegalArgumentException("Cannot add child fields to a map key; keys must be primitive"); Type guard
static boolean isStructParent(Schema schema, int parentFieldId) {
Types.NestedField f = schema.findField(parentFieldId) != null ? schema.findField(parentFieldId) : findNested(schema, parentFieldId);
return f != null && f.type() instanceof Types.StructType;
} Try / catch
try {
updateSchema.apply();
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Cannot add fields to map keys")) throw new IllegalStateException("Parent field must be a struct, not a map key", e);
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot delete element type from list:
- Cannot delete map keys:
- Cannot update map keys:
- Cannot alter map keys:
- Unsorted order ID must be 0
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/04dbd1645c4369d2.
Report an issue: GitHub.