apache/iceberg · error · IllegalArgumentException
Cannot delete map keys:
Error message
Cannot delete map keys:
What it means
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.
Source
Thrown at core/src/main/java/org/apache/iceberg/SchemaUpdate.java:718
elementUpdate != null ? elementUpdate.isOptional() : list.isElementOptional();
if (isElementOptional == elementField.isOptional() && list.elementType() == elementType) {
return list;
}
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();View on GitHub (pinned to 86d9c8fc54)
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)
Example fix
// before updateSchema.delete(mapType.fields().get(0).fieldId()); // key id — throws // after updateSchema.delete(mapColumn.fieldId()); // delete the map column instead
Defensive patterns
Strategy: validation
Validate before calling
Types.MapType map = ...;
int keyId = map.fields().get(0).fieldId();
if (requestedDeletes.contains(keyId)) throw new IllegalArgumentException("Map keys cannot be deleted; delete the map column " + mapColumnId + " instead"); Type guard
static boolean isMapKeyId(Types.NestedField mapColumn) {
return mapColumn.type() instanceof Types.MapType && mapColumn.type().asMapType().fields().get(0).fieldId() != mapColumn.fieldId();
}
// guard: requestedDeleteId != mapType.asMapType().keyId() Try / catch
try {
updateSchema.apply();
} catch (IllegalArgumentException e) {
if (e.getMessage().equals("Cannot delete map keys: " + e.getMessage().substring("Cannot delete map keys: ".length()))) { /* always rebuild message check */ }
if (e.getMessage().startsWith("Cannot delete map keys")) throw new IllegalStateException("Drop and re-add the map column instead", e);
throw e;
} Prevention
- 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
When it happens
Trigger: Calling updateSchema.delete(keyFieldId) where keyFieldId is the internal field ID of a map's key (map.fields().get(0).fieldId()).
Common situations: 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.
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 update map keys:
- Cannot add fields to 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/ee4f81e0852cd6cf.
Report an issue: GitHub.