karatelabs/karate · error · io.karatelabs.js.EngineInterruptedException
<interrupted>
Error message
<interrupted>
What it means
JsPromise.join blocks the calling thread on the promise's future; if that thread is interrupted while waiting, the library restores the interrupt flag and throws EngineInterruptedException ("<interrupted>"). This is the engine's typed wrapper so await-style callers unwind uniformly on cancellation.
Solutions
- Catch EngineInterruptedException and propagate/abort — do not swallow; the interrupt was intentional.
- Ensure awaited promises always settle (resolve/reject) so joins don't linger until interruption.
- Check for deadlock in the promise producer (unresolved inner promise, missing resolve callback).
- If timeouts are expected, pass an explicit timeout instead of relying on interruption.
Example fix
// before var v = await neverSettling(); // hangs until thread interrupted // after var v = await Promise.race([p, Promise.timeout(5000)]); // settles on its own
Defensive patterns
Strategy: try-catch
Validate before calling
// before awaiting, ensure the producer can settle:
if (p == null || typeof p.then !== 'function') throw new TypeError('not a promise'); Type guard
boolean isAwaitable(Object v) { return v != null && tryResolve(v) != null; } // Thenable check per spec Try / catch
try { return p.join(timeout); } catch (EngineInterruptedException e) { Thread.currentThread().interrupt(); return null; /* or rethrow after cleanup */ } Prevention
- Always give awaited promises a bounded timeout so they settle on their own.
- Guarantee resolve/reject on every path of promise-producing code.
- Preserve the interrupt status; never swallow InterruptedException.
- Watch for never-settling promises during shutdown — cancel them explicitly.
When it happens
Trigger: Awaiting (join) a promise whose future never completes while the host thread gets Thread.interrupt() — e.g. Karate step timeout, executor shutdown, or explicit cancellation.
Common situations: Test-suite shutdown while awaiting a never-resolving promise; watchdog timers interrupting the worker thread; await on a promise whose JS producer deadlocked or was cancelled (related to generator HOST_CANCELLED).
Related errors
- error in waitForOutput
- timed out waiting for promise
- Timeout waiting for available driver for scenario
- error waiting for process
- cannot reset while shutting down
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/feadbaacb5d6e1d2.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsPromise.java:240
* Block until settled and return the fulfillment value, throwing
* {@link JsRejectionException} on rejection. For Java callers only — calling
* this from the engine thread would wait for a queue that nothing is
* pumping.
*/
public Object await() {
return join(null);
}
/** {@link #await()} with a deadline; throws {@link EngineTimeoutException}
* if the promise has not settled by then. */
public Object join(Duration timeout) {
try {
return timeout == null
? toFuture().get()
: toFuture().get(Math.max(timeout.toMillis(), 0), TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new EngineInterruptedException();
} catch (TimeoutException e) {
throw new EngineTimeoutException("timed out waiting for promise");
} catch (ExecutionException e) {
Throwable cause = e.getCause() == null ? e : e.getCause();
if (cause instanceof RuntimeException re) {
throw re;
}
throw new EngineException(cause.getMessage(), cause);
}
}
/**
* The reverse association that makes a round trip lossless: handing a
* promise's own {@link #toFuture()} back into JS recovers the original
* {@code JsPromise}, independent of the scope's stage cache.
*/
static final class PromiseView extends CompletableFuture<Object> {
View on GitHub (pinned to a22eb90246)