oracle/graal · error · NoSuchElementException

Empty iterator does not have elements

Error message

Empty iterator does not have elements

What it means

The shared EMPTY_ITERATOR singleton (returned by getKeys() of an empty EconomicMap, iterator() of empty iterables, and EmptySet iteration) throws NoSuchElementException from next() because it yields no elements. hasNext() always returns false; calling next() without checking hasNext() is the classic iteration protocol violation.

Source

Thrown at sdk/src/org.graalvm.collections/src/org/graalvm/collections/EmptyMap.java:87

        public Object getValue() {
            throw new NoSuchElementException("Empty cursor does not have elements");
        }

        @Override
        public Object setValue(Object newValue) {
            throw new NoSuchElementException("Empty cursor does not have elements");
        }
    };

    static final Iterator<Object> EMPTY_ITERATOR = new Iterator<>() {
        @Override
        public boolean hasNext() {
            return false;
        }

        @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

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Always gate next() with hasNext(): while (it.hasNext()) { it.next(); } or use the enhanced-for statement.
  2. Check isEmpty() before obtaining/using the iterator when empties are expected.
  3. Prefer getEntries()/getKeys() with enhanced-for so the protocol cannot be violated.

Example fix

// before
Iterator<K> it = map.getKeys().iterator();
K k = it.next(); // throws on empty map

// after
Iterator<K> it = map.getKeys().iterator();
K k = it.hasNext() ? it.next() : null;
Defensive patterns

Strategy: validation

Validate before calling

Iterator<K> it = map.getKeys().iterator();
K k = it.hasNext() ? it.next() : null;

Prevention

When it happens

Trigger: Calling next() on the iterator returned by an empty EconomicMap.getKeys().iterator(), EmptySet-style iteration, or any Iterable backed by EmptyMap.EMPTY_ITERABLE, without a preceding true hasNext().

Common situations: Hand-written for-loops using a saved iterator after hasNext() returned false; enhanced-for loops are safe, but manual it.next() in while(true) style loops are not; streams/spliterator bridges that call next() eagerly.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/7300163b2707789a. Report an issue: GitHub.