karatelabs/karate · error · JsErrorException

iterator.next is not a function

Error message

iterator.next is not a function

What it means

In the iterator-object wrapper built from a user-supplied iterator object, fetch() reads the `next` member and requires it to be a callable. If the wrapped object's `next` property is missing, null, or not a function, karate throws this TypeError — the object claimed to be an iterator but does not satisfy the iterator protocol.

Solutions

  1. Return an object whose `next` is a function: `{ next: function() { return {value: v, done: b}; } }`.
  2. Do not return a step result object directly as the iterator.
  3. If next is optional in some states, still provide it (e.g. always return `{done:true}` steps).

Example fix

// before
return { value: 1, done: false };
// after
return { next: function() { return { value: 1, done: false }; } };
Defensive patterns

Strategy: validation

Validate before calling

var it = obj[Symbol.iterator]();
if (it == null || typeof it.next !== 'function') throw new TypeError('object is not an iterator');

Type guard

function isIterator(o) { return o != null && typeof o.next === 'function'; }

Try / catch

try { for (var x of obj) { ... } } catch (e) { if (String(e).indexOf('next is not a function') !== -1) { /* use manual index-based loop */ } else { throw e; } }

Prevention

When it happens

Trigger: An object returned from Symbol.iterator has no `next` member or `next` is a non-callable value (e.g. a plain data object `{done:false, value:1}` returned instead of `{next: fn}`), consumed via for-of/spread.

Common situations: Confusing an iterator RESULT object ({value,done}) with an ITERATOR object ({next}), returning the wrong shape from a custom Symbol.iterator, or a typo'd member name (`nxt`, `next()` assigned result).

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/IterUtils.java:204

    }

    /**
     * Walk an already-constructed iterator object's {@code .next()} method to
     * produce a {@link JsIterator}. Shared by {@link #userIterator} (which
     * first invokes {@code @@iterator}) and the spec-shaped branch of
     * {@link #iteratorFromCallable}.
     */
    private static JsIterator iteratorObjectWalker(ObjectLike iterObj, Context context) {
        return new JsIterator() {
            Object pending;
            boolean fetched;
            boolean done;

            private void fetch() {
                if (fetched || done) return;
                Object nextFn = iterObj.getMember("next");
                if (!(nextFn instanceof JsCallable nextCallable)) {
                    throw JsErrorException.typeError("iterator.next is not a function");
                }
                Object step;
                if (context instanceof CoreContext cc) {
                    Object savedThis = cc.thisObject;
                    cc.thisObject = iterObj;
                    try {
                        step = nextCallable.call(cc, EMPTY_ARGS);
                    } finally {
                        cc.thisObject = savedThis;
                    }
                } else {
                    step = nextCallable.call(context, EMPTY_ARGS);
                }
                if (isJsErrored(context)) { done = true; return; }
                if (!(step instanceof ObjectLike stepObj)) {
                    throw JsErrorException.typeError("iterator result is not an object");
                }
                if (Terms.isTruthy(readMember(stepObj, "done", context))) {

View on GitHub (pinned to a22eb90246)