karatelabs/karate · error · java.util.NoSuchElementException

NoSuchElementException

Error message

NoSuchElementException

What it means

JsArray's internal KeyValue iterator throws java.util.NoSuchElementException when next() is called after the array's entries are exhausted. The library's own iteration loops always guard with hasNext(); a raw next() past the end means an iteration protocol bug or misuse of the iterator. In JS semantics, calling an exhausted iterator's next() should return {done:true}, never throw.

Solutions

  1. Guard every next() call with hasNext() before consuming.
  2. Do not share one iterator across multiple consumers; obtain a fresh iterator per loop.
  3. If it fires during normal JS for...of, report/check for mid-iteration mutation of the array (splice/length changes) and snapshot before iterating.
  4. Upgrade karate-js — later versions harden iterator bounds.

Example fix

// before
while (true) { KeyValue kv = it.next(); ... }
// after
while (it.hasNext()) { KeyValue kv = it.next(); ... }
Defensive patterns

Strategy: try-catch

Validate before calling

if (arr == null || arr.length === 0) return; // skip iteration entirely

Type guard

boolean canAdvance(Iterator<?> it) { return it != null && it.hasNext(); }

Try / catch

try { while (it.hasNext()) { process(it.next()); } } catch (NoSuchElementException e) { log.warn("iterator over-advanced", e); }

Prevention

When it happens

Trigger: Calling next() on the JsArray entry iterator without checking hasNext() after all elements have been consumed; an engine-internal loop or custom host code advancing the iterator more times than the array has entries.

Common situations: Custom Java host code iterating a Karate JS array; engine bugs during for...of/entries() enumeration after array mutation; concurrent consumption of the same iterator from two loops.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/3eda910dcbd41f47. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsArray.java:988

                    if (parseIndex(s.name) >= 0) continue;
                    if ("length".equals(s.name)) continue;
                    Object val = ctx != null ? s.read(JsArray.this, ctx)
                            : (s instanceof DataSlot ds ? ds.value : null);
                    peeked = new KeyValue(JsArray.this, yieldCount++, s.name, val);
                    return true;
                }
                peeked = null;
                return false;
            }

            @Override
            public boolean hasNext() {
                return peeked != null || advance();
            }

            @Override
            public KeyValue next() {
                if (peeked == null && !advance()) throw new NoSuchElementException();
                KeyValue kv = peeked;
                peeked = null;
                return kv;
            }
        };
    }

    // =================================================================================================
    // Helper methods
    // =================================================================================================

    static JsArray toArray(Map<String, Object> map) {
        List<Object> list = new ArrayList<>();
        if (map.containsKey("length")) {
            Object length = map.get("length");
            if (length instanceof Number) {
                int size = ((Number) length).intValue();
                for (int i = 0; i < size; i++) {

View on GitHub (pinned to a22eb90246)