{"record":{"id":"01f17e63d2242f21","repo":"karatelabs/karate","slug":"nosuchelementexception-jsmapprototype","errorCode":null,"errorMessage":"NoSuchElementException","messagePattern":"NoSuchElementException","errorType":"exception","errorClass":"java.util.NoSuchElementException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsMapPrototype.java","lineNumber":206,"sourceCode":"    /**\n     * Iterator that walks the map's entries in insertion order. Per spec, mutations\n     * during iteration are observed (entries added after the cursor are visited;\n     * deleted entries are skipped). Implemented by snapshotting the keys lazily at\n     * each {@code next()} via a fresh entry iterator.\n     */\n    private static JsIterator mapIterator(JsMap m, MapIteratorKind kind) {\n        return new JsIterator() {\n            int cursor = 0;\n\n            @Override\n            public boolean hasNext() {\n                return cursor < m.entries.size();\n            }\n\n            @Override\n            public Object next() {\n                if (cursor >= m.entries.size()) {\n                    throw new NoSuchElementException();\n                }\n                // LinkedHashMap preserves insertion order; advance cursor in step with the\n                // sequential view. This is O(n) per step in the worst case but correct under\n                // mid-iteration mutation; the test262 suite exercises tiny maps.\n                Iterator<Map.Entry<Object, Object>> it = m.entries.entrySet().iterator();\n                for (int i = 0; i < cursor; i++) it.next();\n                Map.Entry<Object, Object> e = it.next();\n                cursor++;\n                return switch (kind) {\n                    case KEY -> e.getKey();\n                    case VALUE -> e.getValue();\n                    case KEY_VALUE -> {\n                        List<Object> pair = new ArrayList<>(2);\n                        pair.add(e.getKey());\n                        pair.add(e.getValue());\n                        yield pair;\n                    }\n                };","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsMapPrototype.java#L188-L224","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nwhile (true) { var e = it.next(); if (e.done) break; ... }\n// after\nvar e; while (!(e = it.next()).done) { ... } // single drain, no over-advance","handlingStrategy":"type-guard","validationCode":"if (!(m instanceof Map) || m.size === 0) return; // nothing to iterate","typeGuard":"function nextSafe(it) { const r = it.next(); return r.done ? null : r.value; }","tryCatchPattern":"try { let r; while (!(r = it.next()).done) { handle(r.value); } } catch (e) { if (isNoSuchElement(e)) { /* iterator already drained */ } else throw e; }","preventionTips":["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."],"tags":["javascript","map","iterator"],"backgroundTag":"index-out-of-bounds","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}