oracle/graal · error · NoSuchElementException
Empty cursor does not have elements
Error message
Empty cursor does not have elements
What it means
MapCursor.remove() on the shared EMPTY_CURSOR singleton (returned by EconomicMap.getEntries() for an empty map) always throws NoSuchElementException. An empty cursor is positioned on no element, so there is nothing to remove; the library treats calling a cursor method that requires a current element as an iteration error, mirroring java.util.Iterator semantics.
Source
Thrown at sdk/src/org.graalvm.collections/src/org/graalvm/collections/EmptyMap.java:55
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.graalvm.collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.BiFunction;
/**
* Singleton instances for empty maps and the corresponding iterators and cursors.
*/
class EmptyMap {
static final MapCursor<Object, Object> EMPTY_CURSOR = new MapCursor<>() {
@Override
public void remove() {
throw new NoSuchElementException("Empty cursor does not have elements");
}
@Override
public boolean advance() {
return false;
}
@Override
public Object getKey() {
throw new NoSuchElementException("Empty cursor does not have elements");
}
@Override
public Object getValue() {
throw new NoSuchElementException("Empty cursor does not have elements");
}
@OverrideView on GitHub (pinned to a66e9ccd1d)
Solutions
- Only call cursor.remove() after cursor.advance() has returned true, exactly once per element.
- Check map.isEmpty() (or !cursor.advance()) before performing cursor operations.
- Prefer map.removeKey(key) over cursor-based removal when you already know the key.
Example fix
// before
MapCursor<K,V> c = map.getEntries();
while (c.advance()) { ... }
c.remove(); // wrong: cursor exhausted / empty
// after
MapCursor<K,V> c = map.getEntries();
while (c.advance()) {
if (shouldDrop(c.getKey())) {
c.remove(); // valid: current element exists
}
} Defensive patterns
Strategy: validation
Validate before calling
if (!map.isEmpty()) {
MapCursor<K,V> c = map.getEntries();
while (c.advance()) {
if (drop(c.getKey())) c.remove(); // remove only while positioned
}
} Prevention
- Treat MapCursor like Iterator: mutate only between a true advance() and the next advance().
- Prefer map.removeKey(key) when the key is already known.
- Never call cursor methods after the loop exits.
When it happens
Trigger: Obtaining a cursor from an empty EconomicMap via map.getEntries() and calling remove() without a preceding successful advance(). Note the cursor starts 'before' the first element; remove() is only valid after advance() returned true. Also triggered by calling remove() twice after one advance().
Common situations: Generic iteration code written for java.util.Map.entrySet().iterator() ported to MapCursor; cleanup loops that call remove() unconditionally per iteration; cursors obtained from EconomicMaps.createMap() that is later emptied by clear() before iteration.
Related errors
- Empty iterator does not have elements
- map grown too large!
- endless collision link cycle, most likely due to unsynchroni
- null not supported
- Cannot modify the always-empty map
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/18145310a8137643.
Report an issue: GitHub.