apache/iceberg · error · IllegalArgumentException
Cannot alter map keys:
Error message
Cannot alter map keys:
What it means
After the SchemaUpdate visitor recursively computes the new key type (kResult), it verifies the key type is unchanged: map.keyType().equals(kResult). If any operation altered the key's type despite the earlier guards, this IllegalArgumentException is thrown, enforcing Iceberg's rule that map keys are immutable in schema evolution.
Source
Thrown at core/src/main/java/org/apache/iceberg/SchemaUpdate.java:724
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;
}
if (isValueOptional) {View on GitHub (pinned to 86d9c8fc54)
Solutions
- Audit the update operations for anything touching the key field's type and remove it
- Ensure updates are applied only to value fields and non-key columns
- Build a new map column (drop + add) if a key type change is genuinely required
Example fix
// before // custom visitor that widens all int keys to long via updateColumn updateSchema.updateColumn(mapValueParentFieldId, ...); // indirectly altering key type → throws // after // keep key type fixed; widen only the value updateSchema.updateColumn(valueFieldId, Types.LongType.get());
Defensive patterns
Strategy: try-catch
Validate before calling
Types.MapType map = ...;
if (!map.keyType().equals(originalKeyType)) throw new IllegalArgumentException("Update must not change map key type " + originalKeyType); Try / catch
try {
updateSchema.apply();
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Cannot alter map keys")) throw new IllegalStateException("Map key type changed during update — review combined operations touching the key field", e);
throw e;
} Prevention
- Keep map key types fixed across schema evolution; evolve only value types
- Review multi-operation updates for transitive effects on key fields
- If a key type change is unavoidable, plan a drop + re-add with data rewrite
When it happens
Trigger: A schema update whose composed operations cause the map key type to change between the original and rebuilt schema (e.g. combined update primitives reaching the key field through a custom TypeUtil visit), detected during SchemaUpdate.apply.
Common situations: Complex multi-operation schema updates assembled programmatically where per-field guards were bypassed; custom UpdateSchema implementations or visitor overrides that transform types beneath the earlier deletes/updates/adds checks.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot delete element type from list:
- Cannot delete map keys:
- Cannot update map keys:
- Cannot add fields to map keys:
- Unsorted order ID must be 0
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/8fb27f1fc7ce2fca.
Report an issue: GitHub.