karatelabs/karate · error · JsErrorException

Result of iterator method is not an object

Error message

Result of iterator method is not an object

What it means

iteratorFromCallable wraps a JS factory/callable that produces a custom iterator. Per the iterator protocol, the Symbol.iterator method (or factory) must return an object. If it returns null or undefined, karate throws this TypeError, mirroring the spec's 'Result of the Symbol.iterator method is not an object' check for user-supplied iterator factories.

Solutions

  1. Make the Symbol.iterator method return an iterator object: `return { next: function() { return {done:true, value:undefined}; } }`.
  2. Add an explicit `return` for every code path in the factory, including early-exit branches.
  3. Return a generator result (`function*() {...}` style via karate's supported constructs) instead of a bare function with no return.

Example fix

// before
obj[Symbol.iterator] = function() {
  var i = 0;
};
// after
obj[Symbol.iterator] = function() {
  var i = 0;
  return { next: function() { return i < 3 ? {done:false, value:i++} : {done:true}; } };
};
Defensive patterns

Strategy: type-guard

Validate before calling

var r = obj[Symbol.iterator]();
if (r == null || typeof r !== 'object') throw new TypeError('iterator factory must return an object');

Type guard

function returnsIteratorObject(fn) { var r = fn(); return r != null && typeof r === 'object'; }

Try / catch

try { for (var x of obj) { ... } } catch (e) { if (String(e).indexOf('not an object') !== -1) { /* fall back to manual iteration */ } else { throw e; } }

Prevention

When it happens

Trigger: A JS object's Symbol.iterator method (or a callable passed to iteratorFromCallable) executes and returns null or undefined instead of an iterator object, e.g. `obj[Symbol.iterator] = function(){}` with no return statement.

Common situations: Hand-written custom iterators in Karate JS scripts where the author forgot the `return { next: ... }` statement, or an iterator factory that early-returns on an edge condition.

Related errors


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

Appendix: source

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

     * shortcuts still iterate correctly. test262 tests like
     * {@code converts-negative-zero.js} construct set-likes that return
     * {@code [-0].values()} from {@code keys} expecting iteration to work.
     */
    public static JsIterator iteratorFromCallable(JsCallable factory, ObjectLike receiver, Context context) {
        Object result;
        if (context instanceof CoreContext cc) {
            Object savedThis = cc.thisObject;
            cc.thisObject = receiver;
            try {
                result = factory.call(cc, EMPTY_ARGS);
            } finally {
                cc.thisObject = savedThis;
            }
        } else {
            result = factory.call(context, EMPTY_ARGS);
        }
        if (result == null || result == Terms.UNDEFINED) {
            throw JsErrorException.typeError("Result of iterator method is not an object");
        }
        // Spec-shaped iterator object: ObjectLike with a callable .next.
        if (result instanceof ObjectLike obj) {
            Object nextFn = obj.getMember("next");
            if (nextFn instanceof JsCallable) {
                return iteratorObjectWalker(obj, context);
            }
        }
        // Fallback: engine-internal shortcut returned a List / JsArray /
        // String / iterable ObjectLike — getIterator's tryGetIterator covers
        // all of those.
        return getIterator(result, context);
    }

    /**
     * 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

View on GitHub (pinned to a22eb90246)