{"record":{"id":"cc20c70e0a151f07","repo":"karatelabs/karate","slug":"timed-out-waiting-for-promise","errorCode":null,"errorMessage":"timed out waiting for promise","messagePattern":"timed out waiting for promise","errorType":"exception","errorClass":"io.karatelabs.js.EngineTimeoutException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsPromise.java","lineNumber":242,"sourceCode":"     * this from the engine thread would wait for a queue that nothing is\n     * pumping.\n     */\n    public Object await() {\n        return join(null);\n    }\n\n    /** {@link #await()} with a deadline; throws {@link EngineTimeoutException}\n     *  if the promise has not settled by then. */\n    public Object join(Duration timeout) {\n        try {\n            return timeout == null\n                    ? toFuture().get()\n                    : toFuture().get(Math.max(timeout.toMillis(), 0), TimeUnit.MILLISECONDS);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new EngineInterruptedException();\n        } catch (TimeoutException e) {\n            throw new EngineTimeoutException(\"timed out waiting for promise\");\n        } catch (ExecutionException e) {\n            Throwable cause = e.getCause() == null ? e : e.getCause();\n            if (cause instanceof RuntimeException re) {\n                throw re;\n            }\n            throw new EngineException(cause.getMessage(), cause);\n        }\n    }\n\n    /**\n     * The reverse association that makes a round trip lossless: handing a\n     * promise's own {@link #toFuture()} back into JS recovers the original\n     * {@code JsPromise}, independent of the scope's stage cache.\n     */\n    static final class PromiseView extends CompletableFuture<Object> {\n\n        final JsPromise owner;\n","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsPromise.java#L224-L260","documentation":"join(timeout) waits on the promise future with a deadline; when it elapses, TimeoutException is translated into EngineTimeoutException(\"timed out waiting for promise\"). It means the awaited promise did not settle within the allowed time — the JS producer never resolved or rejected.","triggerScenarios":"await/join with a non-null timeout on a promise that stays pending: unresolved executor callback, a network call with no response, a generator that never resumes, or a timeout set smaller than the work required.","commonSituations":"Waiting on a fetch/backend call that hangs; forgetting to call resolve() in a Promise constructor; overly tight timeout configured in Karate steps wrapping async JS; deadlocked generator chain.","solutions":["Increase the timeout passed to join/await if the operation is legitimately slow.","Audit the promise producer: ensure resolve/reject is always invoked on every code path.","Add an upstream timeout to the slow operation (HTTP client timeout) so the promise rejects instead of hanging forever.","Catch EngineTimeoutException and apply retry/fallback logic for transient slowness."],"exampleFix":"// before\nnew Promise((resolve) => { /* resolve never called */ })\n// after\nnew Promise((resolve, reject) => { setTimeout(() => resolve(val), 100); })","handlingStrategy":"retry","validationCode":"// pre-check the awaited operation's own timeout is smaller than the join timeout:\nif (timeout != null && upstreamTimeout > timeout.toMillis()) warn(\"join timeout shorter than upstream timeout\");","typeGuard":null,"tryCatchPattern":"try { return p.join(timeout); } catch (EngineTimeoutException e) { log.warn(\"promise did not settle within \" + timeout); return fallback(); }","preventionTips":["Size the timeout to the slowest realistic upstream call plus margin.","Put timeouts on the underlying operations (HTTP client, scheduler) so promises reject rather than hang.","Audit Promise constructors for missing resolve/reject calls.","Apply retry with backoff only for idempotent awaited operations."],"tags":["promise","timeout","concurrency"],"backgroundTag":"request-timeout","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}