karatelabs/karate · error · io.karatelabs.js.Abrupt
<JS rejection reason>
Error message
<JS rejection reason>
What it means
checkAbrupt converts a pending cooperative throw recorded on the Context into an Abrupt carrying the JS rejection reason, clearing the pending-error flag. Callers (asPromise, collect — e.g. Promise.all/allSettled/race/any iteration) use it so an in-flight script error surfaces as the promise's rejection reason instead of being silently dropped.
Solutions
- Find and fix the original JS throw — the Abrupt's payload is that reason; read its message/stack.
- Don't swallow errors inside iterator callbacks; let them reject the promise explicitly.
- Avoid continuing script execution after an uncaught sync error; check/reset context error state in host code.
- Wrap risky sections in try/catch in JS so errors become deliberate rejections.
Example fix
// before
arr.map(() => { throw new Error('boom'); }); // pending error surfaces later as Abrupt
// after
Promise.all(arr.map(() => Promise.reject(new Error('boom')))).catch(handle); // explicit rejection Defensive patterns
Strategy: try-catch
Validate before calling
// in host code before running combinators: ensure no pending error if (context instanceof CoreContext cc && cc.isError()) cc.reset(); // or handle it first
Try / catch
try { return Promise.all(...); } catch (Abrupt a) { handleRejection(a.value); /* a.value is the original JS rejection reason */ } Prevention
- Fix the originating JS throw — the Abrupt payload is that reason's value.
- Make iterator callbacks reject promises explicitly instead of throwing sync errors mid-enumeration.
- In host embedding code, check and clear context error state between script evaluations.
- Wrap user callbacks in try/catch and convert to Promise.reject for predictable handling.
When it happens
Trigger: During Promise combinator iteration (asPromise/collect), the context has isError() set — a prior JS throw is pending — so the pending error value is taken as the rejection reason and thrown as Abrupt.
Common situations: A callback passed to Promise.all's iterator throws mid-iteration; an earlier statement threw and the error is only observed at the next combinator boundary; user code mixing sync throws with async combinators.
Related errors
- Promise requires an engine
- Promise requires an active evaluation
- Promise constructor cannot be invoked without 'new'
- Promise resolver is not a function
- Promise combinator called on a non-constructor
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/7fc083834a6d1ae8.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsPromiseConstructor.java:165
* itself completes normally with a rejected promise.
*/
private static final class Abrupt extends RuntimeException {
final transient Object reason;
Abrupt(Object reason) {
super(null, null, false, false);
this.reason = reason;
}
}
/** Converts a pending cooperative throw into an {@link Abrupt}, clearing the
* flag — from here on the error travels as the rejection reason. */
private static void checkAbrupt(Context context) {
if (context instanceof CoreContext cc && cc.isError()) {
Object reason = cc.getErrorThrown();
cc.reset();
throw new Abrupt(reason);
}
}
/** IteratorClose with the surrounding completion already abrupt: whatever
* {@code return()} does is discarded, the original reason wins. */
private static void closeQuietly(JsIterator iter, Context context) {
try {
iter.close(context, true);
} catch (RuntimeException e) {
if (e instanceof FlowControlSignal || AsyncSupport.isHostCancellation(e)) {
throw e;
}
// IteratorClose failing is swallowed per spec 7.4.6 step 4
}
if (context instanceof CoreContext cc && cc.isStopped()) {
cc.reset(); // close() re-parks the completion it saw — we own the reason now
}
}View on GitHub (pinned to a22eb90246)