karatelabs/karate · error · JsErrorException
The iterator does not provide a 'throw' method
Error message
The iterator does not provide a 'throw' method
What it means
When a throw completion is sent into a delegated iterator (yield* with .throw()), and the iterator object has no 'throw' method at all, the engine reports that the iterator does not provide a 'throw' method. This is the ECMAScript-specified message for the yield* delegation path; it follows IteratorClose of the inner iterator first.
Solutions
- Add a throw method to the custom iterator object
- Replace the hand-rolled iterator with a generator function, which provides next/return/throw automatically
- Avoid calling .throw() on the outer generator while it is delegated into a plain iterator
Example fix
// before
const it = { next() { ... } }; // no throw
// after
function* gen() { ... } // generator supplies throw/return Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof innerIterator.throw !== 'function') { /* avoid delegating throw into this iterator */ } Type guard
function supportsThrow(it) { return it != null && typeof it.throw === 'function'; } Try / catch
try { gen.throw(e); } catch (err) { if (String(err).includes("does not provide a 'throw'")) { gen.return(undefined); /* close cleanly instead */ } } Prevention
- Only delegate throw into generators or iterators known to implement throw()
- Close the outer generator with .return() when the inner iterator lacks throw
- Wrap inner iterators with a generator adapter that adds default throw/return
When it happens
Trigger: Calling generator.throw(err) on a generator that is currently suspended inside a yield* delegating to a custom iterator lacking a throw method, or for-of/iterator code paths that forward throw completions to a plain iterator object.
Common situations: Hand-rolled iterator objects (only next(), maybe return()) delegated to via yield*; consumers expecting full generator protocol from plain iterators; mixing generator throw with arrays wrapped through the generic iterator adapter.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- iterator result is not an object
- 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/61d6cd35eff3822c.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/Interpreter.java:2975
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 -> {
Object returned = invokeIteratorMethod(iterObj, "return", sent, context, false);
if (context.isStopped()) {View on GitHub (pinned to a22eb90246)