karatelabs/karate · error · java.util.NoSuchElementException
NoSuchElementException
Error message
NoSuchElementException
What it means
The Map.prototype entries/keys/values iterator throws NoSuchElementException when next() is called on an exhausted map iterator (cursor >= number of entries). In correct JS, next() on a done iterator returns {done:true}; this Java exception means a caller — typically engine-internal — advanced past the end without checking.
Solutions
- Check it.next()/result.done before reading value in JS; in Java guard with hasNext().
- Snapshot map entries (Array.from(map)) before iterating if the map is mutated during iteration.
- Use a fresh iterator per loop; never resume a partially consumed one.
- Upgrade karate-js if it fires from library-internal iteration.
Example fix
// before
while (true) { var e = it.next(); if (e.done) break; ... }
// after
var e; while (!(e = it.next()).done) { ... } // single drain, no over-advance Defensive patterns
Strategy: type-guard
Validate before calling
if (!(m instanceof Map) || m.size === 0) return; // nothing to iterate
Type guard
function nextSafe(it) { const r = it.next(); return r.done ? null : r.value; } Try / catch
try { let r; while (!(r = it.next()).done) { handle(r.value); } } catch (e) { if (isNoSuchElement(e)) { /* iterator already drained */ } else throw e; } Prevention
- Single-drain iterators: never re-iterate a partially consumed Map iterator.
- Snapshot with Array.from(map) when mutating during iteration.
- Always respect the done flag instead of blindly calling next().
- In Java, wrap manual draining in hasNext() checks.
When it happens
Trigger: Calling next() on a Map iterator after every entry has been yielded; mutating the map mid-iteration (add/delete) so the cursor/size accounting desyncs; consuming one iterator from multiple places.
Common situations: JS code like `for (const [k,v] of m)` where the callback throws and a retry re-drains the same iterator; host Java code draining the iterator manually; test262-style tiny-map edge cases with concurrent mutation.
Related errors
- Iterator value is not an entry object
- filterKeys() needs at least two arguments
- NoSuchElementException
- NoSuchElementException
- NoSuchElementException
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/01f17e63d2242f21.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsMapPrototype.java:206
/**
* Iterator that walks the map's entries in insertion order. Per spec, mutations
* during iteration are observed (entries added after the cursor are visited;
* deleted entries are skipped). Implemented by snapshotting the keys lazily at
* each {@code next()} via a fresh entry iterator.
*/
private static JsIterator mapIterator(JsMap m, MapIteratorKind kind) {
return new JsIterator() {
int cursor = 0;
@Override
public boolean hasNext() {
return cursor < m.entries.size();
}
@Override
public Object next() {
if (cursor >= m.entries.size()) {
throw new NoSuchElementException();
}
// LinkedHashMap preserves insertion order; advance cursor in step with the
// sequential view. This is O(n) per step in the worst case but correct under
// mid-iteration mutation; the test262 suite exercises tiny maps.
Iterator<Map.Entry<Object, Object>> it = m.entries.entrySet().iterator();
for (int i = 0; i < cursor; i++) it.next();
Map.Entry<Object, Object> e = it.next();
cursor++;
return switch (kind) {
case KEY -> e.getKey();
case VALUE -> e.getValue();
case KEY_VALUE -> {
List<Object> pair = new ArrayList<>(2);
pair.add(e.getKey());
pair.add(e.getValue());
yield pair;
}
};View on GitHub (pinned to a22eb90246)