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
Karate's JS engine evaluates spread/destructuring/for-of by calling the operand's Symbol.iterator method; the spec requires that call to return an object. The engine throws this TypeError when Symbol.iterator exists and is callable but returns a non-object (e.g. undefined, a number, or a primitive). It enforces ECMAScript GetIterator semantics on custom iterator implementations.
Solutions
- Make Symbol.iterator return an object — typically `{ next() { ... } }` or a generator function result
- Convert the method to a generator (`*[Symbol.iterator]() { ... }`) so the engine returns the iterator object automatically
- If the value may not be iterable, guard with a check before spreading or looping
Example fix
// before
const obj = { *[Symbol.iterator]() {} }; // fine, but:
const bad = { [Symbol.iterator]() { const it = makeIter(); } }; // no return
// after
const good = { [Symbol.iterator]() { return makeIter(); } }; Defensive patterns
Strategy: validation
Validate before calling
// JS
function isIterable(x) { return x != null && typeof x[Symbol.iterator] === 'function'; }
if (!isIterable(obj)) throw new TypeError('not iterable'); Type guard
function isIterableWithIterator(x) {
const it = x != null && typeof x[Symbol.iterator] === 'function' ? x[Symbol.iterator]() : null;
return it !== null && typeof it === 'object';
} Try / catch
try { for (const v of obj) { /* ... */ } } catch (e) { if (String(e).includes('Symbol.iterator')) { /* fall back to non-iterable handling */ } } Prevention
- Prefer generator methods (*[Symbol.iterator]()) over hand-built iterator factories
- Always return an object from Symbol.iterator
- Test spread/destructuring of custom collections in unit tests
When it happens
Trigger: A user-defined JS object defines a callable Symbol.iterator whose body returns undefined, a primitive, or forgets a return statement, and the object is then spread (...obj), destructured, or used in for-of.
Common situations: Hand-written iterator classes where the factory function returns nothing; iterators written for another engine that rely on implicit returns; refactoring that turned `return { next() {...} }` into just building the object without returning it.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- iterator result is not an object
- The iterator does not provide a 'throw' method
- iterator.throw is not a function
- iterator. is not a function
- Iterator value is not an entry object
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/342c41fe1d4dfbaf.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/Interpreter.java:2940
* over the raw iterator record (iterator object + its methods invoked
* with arguments), NOT the value-only JsIterator walk: sent values,
* throw/return forwarding, and the delegate's final completion value all
* survive. Each re-yield goes through the same activation handoff, so
* the next resume kind comes from whatever the driver sends.
*/
private static Object evalYieldStar(Object operand, CoreContext context, GeneratorActivation act) {
// GetIterator: call operand[@@iterator]() with operand as `this`
JsIterator probe = null; // only to reuse getIterator's TypeError wording on non-iterables
Object iteratorFn = operand instanceof ObjectLike ol
? ol.getMember(IterUtils.SYMBOL_ITERATOR, ol, context) : null;
ObjectLike iterObj;
if (iteratorFn instanceof JsCallable callable && operand instanceof ObjectLike receiver) {
Object iter = callWith(callable, receiver, context);
if (context.isStopped()) {
return Terms.UNDEFINED;
}
if (!(iter instanceof ObjectLike io)) {
throw JsErrorException.typeError("Result of the Symbol.iterator method is not an object");
}
iterObj = io;
} else {
// strings / raw lists / Java iterables — wrap the engine iterator
// in the standard iterator-object shape so one loop serves all
probe = IterUtils.getIterator(operand, context);
iterObj = IterUtils.toIteratorObject(probe);
}
GeneratorActivation.ResumeKind kind = GeneratorActivation.ResumeKind.NEXT;
Object sent = Terms.UNDEFINED;
while (true) {
Object step;
switch (kind) {
case NEXT -> {
step = invokeIteratorMethod(iterObj, "next", sent, context, true);
if (context.isStopped()) {
return Terms.UNDEFINED;
}View on GitHub (pinned to a22eb90246)