oracle/graal · error · IllegalArgumentException
Cannot modify the always-empty map
Error message
Cannot modify the always-empty map
What it means
EconomicMap.createMap() may return the immutable always-empty singleton EmptyMap.EMPTY_MAP when an initial capacity of 0 is requested. Any structural mutation — put(key, value) — throws IllegalArgumentException('Cannot modify the always-empty map'). The singleton is deliberately immutable so accidental writes fail fast instead of silently dropping data. Note checkNonNull(key) runs first, so a null key on an empty map throws UnsupportedOperationException instead.
Source
Thrown at sdk/src/org.graalvm.collections/src/org/graalvm/collections/EmptyMap.java:102
@Override
public Object next() {
throw new NoSuchElementException("Empty iterator does not have elements");
}
};
static final Iterable<Object> EMPTY_ITERABLE = new Iterable<>() {
@Override
public Iterator<Object> iterator() {
return EMPTY_ITERATOR;
}
};
static final EconomicMap<Object, Object> EMPTY_MAP = new EconomicMap<>() {
@Override
public Object put(Object key, Object value) {
EconomicMapImpl.checkNonNull(key);
throw new IllegalArgumentException("Cannot modify the always-empty map");
}
@Override
public void clear() {
throw new IllegalArgumentException("Cannot modify the always-empty map");
}
@Override
public Object removeKey(Object key) {
EconomicMapImpl.checkNonNull(key);
throw new IllegalArgumentException("Cannot modify the always-empty map");
}
@Override
public Object get(Object key) {
EconomicMapImpl.checkNonNull(key);
return null;
}View on GitHub (pinned to a66e9ccd1d)
Solutions
- Create the map with a positive initial capacity (e.g. EconomicMap.createMap(1)) when you intend to insert, or use the no-capacity overload createMap().
- Before putting, test map == EconomicMap.createMap(0) style singletons indirectly by always allocating growable maps for mutable use.
- If a map may stay empty but is later mutated, never request capacity 0.
Example fix
// before EconomicMap<K,V> m = EconomicMap.createMap(src.size()); // src empty -> capacity 0 -> singleton m.put(k, v); // throws // after EconomicMap<K,V> m = EconomicMap.createMap(Math.max(1, src.size())); m.put(k, v);
Defensive patterns
Strategy: validation
Validate before calling
EconomicMap<K,V> m = EconomicMap.createMap(Math.max(1, expectedSize)); // never capacity 0 for mutable use
Prevention
- Never pass 0 capacity to createMap for maps that will receive puts.
- Compute capacities with Math.max(1, n).
- Reserve capacity-0/empty singleton maps for read-only use.
When it happens
Trigger: Calling put() on the map returned by EconomicMap.createMap(0) (or EconomicMap.create(EconomicMapUtil) with zero capacity) — this returns the shared EMPTY_MAP singleton, not a growable instance.
Common situations: Sizing maps from a variable that computes to 0 (e.g. createMap(other.size()) when other is empty); 'clone-then-populate' patterns that start from an empty copy; versions of code that previously used HashMap and tolerated put on a zero-sized map.
Related errors
- map grown too large!
- endless collision link cycle, most likely due to unsynchroni
- null not supported
- Cannot modify the always-empty set
- Data field must be final if public
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/b15f848a9dd5a720.
Report an issue: GitHub.