{"record":{"id":"81b14e96eb3a25fb","repo":"karatelabs/karate","slug":"result-of-iterator-method-is-not-an-object","errorCode":null,"errorMessage":"Result of iterator method is not an object","messagePattern":"Result of iterator method is not an object","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/IterUtils.java","lineNumber":173,"sourceCode":"     * shortcuts still iterate correctly. test262 tests like\n     * {@code converts-negative-zero.js} construct set-likes that return\n     * {@code [-0].values()} from {@code keys} expecting iteration to work.\n     */\n    public static JsIterator iteratorFromCallable(JsCallable factory, ObjectLike receiver, Context context) {\n        Object result;\n        if (context instanceof CoreContext cc) {\n            Object savedThis = cc.thisObject;\n            cc.thisObject = receiver;\n            try {\n                result = factory.call(cc, EMPTY_ARGS);\n            } finally {\n                cc.thisObject = savedThis;\n            }\n        } else {\n            result = factory.call(context, EMPTY_ARGS);\n        }\n        if (result == null || result == Terms.UNDEFINED) {\n            throw JsErrorException.typeError(\"Result of iterator method is not an object\");\n        }\n        // Spec-shaped iterator object: ObjectLike with a callable .next.\n        if (result instanceof ObjectLike obj) {\n            Object nextFn = obj.getMember(\"next\");\n            if (nextFn instanceof JsCallable) {\n                return iteratorObjectWalker(obj, context);\n            }\n        }\n        // Fallback: engine-internal shortcut returned a List / JsArray /\n        // String / iterable ObjectLike — getIterator's tryGetIterator covers\n        // all of those.\n        return getIterator(result, context);\n    }\n\n    /**\n     * Walk an already-constructed iterator object's {@code .next()} method to\n     * produce a {@link JsIterator}. Shared by {@link #userIterator} (which\n     * first invokes {@code @@iterator}) and the spec-shaped branch of","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/IterUtils.java#L155-L191","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the Symbol.iterator method return an iterator object: `return { next: function() { return {done:true, value:undefined}; } }`.","Add an explicit `return` for every code path in the factory, including early-exit branches.","Return a generator result (`function*() {...}` style via karate's supported constructs) instead of a bare function with no return."],"exampleFix":"// before\nobj[Symbol.iterator] = function() {\n  var i = 0;\n};\n// after\nobj[Symbol.iterator] = function() {\n  var i = 0;\n  return { next: function() { return i < 3 ? {done:false, value:i++} : {done:true}; } };\n};","handlingStrategy":"type-guard","validationCode":"var r = obj[Symbol.iterator]();\nif (r == null || typeof r !== 'object') throw new TypeError('iterator factory must return an object');","typeGuard":"function returnsIteratorObject(fn) { var r = fn(); return r != null && typeof r === 'object'; }","tryCatchPattern":"try { for (var x of obj) { ... } } catch (e) { if (String(e).indexOf('not an object') !== -1) { /* fall back to manual iteration */ } else { throw e; } }","preventionTips":["Always end iterator factories with an explicit return of {next: fn}","Cover every branch of the factory with a return statement","Smoke-test custom iterables with Array.from before use in for-of"],"tags":["javascript","iterator-protocol","typeerror"],"backgroundTag":"unexpected-response-shape","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}