karatelabs/karate · error · JsErrorException
iterator result is not an object
Error message
iterator result is not an object
What it means
During generator-style delegation with iterator 'throw' (e.g. yield* inside a try/catch), Karate invokes the inner iterator's return() method to close it. Per the iterator protocol, if return() is present its result must be an object; the engine throws this TypeError when return() returns a non-object. This mirrors the ECMAScript IteratorClose step.
Solutions
- Make the iterator's return(value) method return an object (typically `{ done: true, value: value }`)
- Convert the inner iterator to a generator so return()/throw() semantics are provided by the engine
- If the iterator cannot implement return(), omit the property entirely so the engine takes the no-return-method path instead of validating its result
Example fix
// before
return() { /* returns undefined */ }
// after
return(v) { return { done: true, value: v }; } Defensive patterns
Strategy: type-guard
Validate before calling
if (it.return && (typeof it.return !== 'function' || !isObj(it.return()))) console.warn('bad return()'); Type guard
function hasValidReturnMethod(it) {
return !('return' in it) || (typeof it.return === 'function' && typeof it.return() === 'object');
} Try / catch
try { gen.throw(err); } catch (e) { if (String(e).includes('iterator result')) { /* normalize iterator or abandon delegation */ } } Prevention
- Implement custom iterators as generators whenever possible
- Give return(v) the contract { done: true, value: v }
- Exercise generator.throw/return paths in tests, not just next()
When it happens
Trigger: A custom iterator object used with yield* (or generator delegation) whose return() method returns undefined or a primitive while the outer generator handles a throw() completion.
Common situations: Custom iterators with a stub return() that returns nothing; iterators ported from looser engines; generator code with try/finally around yield* delegating to a hand-rolled iterator.
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
- The iterator does not provide a 'throw' method
- iterator.throw is not a function
- Generator is already running
- Result of the Symbol.iterator method is not an object
- iterator. is not a function
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/5c174e304d5def19.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/Interpreter.java:2973
step = invokeIteratorMethod(iterObj, "next", sent, context, true);
if (context.isStopped()) {
return Terms.UNDEFINED;
}
}
case THROW -> {
Object throwFn = iterObj.getMember("throw", iterObj, context);
if (context.isStopped()) {
return Terms.UNDEFINED; // a throwing `throw` getter wins outright
}
if (throwFn == null || throwFn == Terms.UNDEFINED) {
// ABSENT throw: close the delegate (validating
// return()'s result when present), then TypeError
Object closed = invokeIteratorMethod(iterObj, "return", null, context, false);
if (context.isStopped()) {
return Terms.UNDEFINED;
}
if (closed != null && !(closed instanceof ObjectLike)) {
throw JsErrorException.typeError("iterator result is not an object");
}
throw JsErrorException.typeError(
"The iterator does not provide a 'throw' method");
}
if (!(throwFn instanceof JsCallable throwCallable)) {
// GetMethod: a PRESENT non-callable throws immediately,
// with no iterator close
throw JsErrorException.typeError("iterator.throw is not a function");
}
step = invokeIteratorCallable(iterObj, throwCallable, sent, context);
if (context.isStopped()) {
return Terms.UNDEFINED;
}
if (!(step instanceof ObjectLike)) {
throw JsErrorException.typeError("iterator result is not an object");
}
}
case RETURN -> {View on GitHub (pinned to a22eb90246)