karatelabs/karate · error · JsErrorException

iterator 'return' is not a function

Error message

iterator 'return' is not a function

What it means

IterUtils.close implements IteratorClose: when a for-of loop exits early (break, throw, return), it calls the iterator's `return` method. Per the spec, if `return` exists it must be callable; if it is a non-callable non-null value and the loop is NOT already unwinding due to an error, karate throws this TypeError (when dueToError is true the bad `return` is ignored so the original error wins).

Solutions

  1. Make `return` a function: `return: function() { cleanup(); return {done:true}; }`.
  2. Remove the invalid `return` member if cleanup is unnecessary — absence is allowed.
  3. Rename any data property that collides with the protocol method name.

Example fix

// before
var it = { next: next, return: false };
// after
var it = { next: next, return: function() { cleanup(); return { done: true }; } };
Defensive patterns

Strategy: type-guard

Validate before calling

if (it.return !== undefined && typeof it.return !== 'function') throw new TypeError("iterator 'return' must be a function");

Type guard

function hasValidReturnMethod(o) { return o.return === undefined || typeof o.return === 'function'; }

Try / catch

try { for (var x of it) { if (x > 10) break; } } catch (e) { if (String(e).indexOf("'return' is not a function") !== -1) { /* cleanup manually */ } else { throw e; } }

Prevention

When it happens

Trigger: Breaking out of (or throwing inside) a for-of over a custom iterator whose object has a `return` property set to a non-function value (e.g. `return: true` as a flag name collision, or `return` assigned to a non-callable).

Common situations: Naming a data member `return` on an iterator object (reserved-word misuse), or implementing return() as a property holding a value instead of a method.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

                // the original completion is a throw it wins, so on dueToError the
                // parked error is restored and anything return() raises is discarded.
                boolean hadError = isJsErrored(ctx);
                Object savedError = hadError ? ((CoreContext) ctx).getErrorThrown() : null;
                if (hadError) {
                    ((CoreContext) ctx).reset();
                }
                try {
                    Object retFn = readMember(iterObj, "return", ctx);
                    if (isJsErrored(ctx)) {
                        if (dueToError) clearError(ctx); // throwing return getter, discard
                        return;
                    }
                    if (retFn == null || retFn == Terms.UNDEFINED) {
                        return; // no return method — nothing to close
                    }
                    if (!(retFn instanceof JsCallable retCallable)) {
                        if (dueToError) return;
                        throw JsErrorException.typeError("iterator 'return' is not a function");
                    }
                    Object result;
                    if (ctx instanceof CoreContext cc) {
                        Object savedThis = cc.thisObject;
                        cc.thisObject = iterObj;
                        try {
                            result = retCallable.call(cc, EMPTY_ARGS);
                        } finally {
                            cc.thisObject = savedThis;
                        }
                    } else {
                        result = retCallable.call(ctx, EMPTY_ARGS);
                    }
                    if (isJsErrored(ctx)) {
                        if (dueToError) clearError(ctx); // return() threw, discard
                        return;                           // else propagate return()'s throw
                    }
                    if (!dueToError && !(result instanceof ObjectLike)) {

View on GitHub (pinned to a22eb90246)