karatelabs/karate · error · JsErrorException

Result of the Symbol.iterator method is not an object

Error message

Result of the Symbol.iterator method is not an object

What it means

In userIterator (the tryGetIterator path for objects with a Symbol.iterator method), karate calls the method and requires the result to be an object per the spec. If Symbol.iterator returns null/undefined or a primitive instead of an iterator object, this TypeError is thrown.

Solutions

  1. Have Symbol.iterator return an object with a callable `next` (e.g. an index-closure iterator).
  2. Return `this` if the object itself already has a `next` method.
  3. Use a generator function (`function*`) as the source when available so the engine builds a valid iterator.

Example fix

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

Strategy: type-guard

Validate before calling

var r = obj[Symbol.iterator] && obj[Symbol.iterator]();
if (r == null || typeof r !== 'object' || typeof r.next !== 'function') throw new TypeError('bad Symbol.iterator result');

Type guard

function implementsIterable(o) { return o != null && typeof o[Symbol.iterator] === 'function' && typeof o[Symbol.iterator]().next === 'function'; }

Try / catch

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

Prevention

When it happens

Trigger: An object defines Symbol.iterator but the method returns null, undefined, a number, or a string — e.g. `obj[Symbol.iterator] = function() { return this.items; }` where items is an array-returning getter misused, or the method forgets to return the iterator.

Common situations: Custom collection classes in Karate JS with a partially implemented iterator protocol, or Symbol.iterator copied from a class where it returns a value rather than an iterator (mixing it up with valueOf-style contracts).

Related errors


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

Appendix: source

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

            Object savedThis = cc.thisObject;
            cc.thisObject = receiver;
            try {
                iter = iteratorFn.call(cc, EMPTY_ARGS);
            } finally {
                cc.thisObject = savedThis;
            }
        } else {
            iter = iteratorFn.call(context, EMPTY_ARGS);
        }
        // A `throw` inside the @@iterator method sets the cooperative stop-flag
        // rather than raising a Java exception. The pending error must win —
        // an exhausted iterator lets the caller unwind without overwriting it
        // with the not-an-object TypeError below.
        if (isJsErrored(context)) {
            return exhaustedIterator();
        }
        if (!(iter instanceof ObjectLike iterObj)) {
            throw JsErrorException.typeError("Result of the Symbol.iterator method is not an object");
        }
        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);

View on GitHub (pinned to a22eb90246)