{"record":{"id":"241d019a51683e30","repo":"karatelabs/karate","slug":"promise-requires-an-engine","errorCode":null,"errorMessage":"Promise requires an engine","messagePattern":"Promise requires an engine","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsPromiseConstructor.java","lineNumber":63,"sourceCode":"    JsPromiseConstructor() {\n        this.name = \"Promise\";\n        this.length = 1;\n        defineOwn(\"prototype\", JsPromisePrototype.INSTANCE, PropertySlot.INTRINSIC);\n        defineOwn(\"resolve\", new JsBuiltinMethod(\"resolve\", 1, resolveDelegate), METHOD_ATTRS);\n        defineOwn(\"reject\", new JsBuiltinMethod(\"reject\", 1, (JsCallable) this::rejectStatic), METHOD_ATTRS);\n        defineOwn(\"all\", new JsBuiltinMethod(\"all\", 1, (JsCallable) this::all), METHOD_ATTRS);\n        defineOwn(\"allSettled\", new JsBuiltinMethod(\"allSettled\", 1, (JsCallable) this::allSettled), METHOD_ATTRS);\n        defineOwn(\"race\", new JsBuiltinMethod(\"race\", 1, (JsCallable) this::race), METHOD_ATTRS);\n        defineOwn(\"any\", new JsBuiltinMethod(\"any\", 1, (JsCallable) this::any), METHOD_ATTRS);\n    }\n\n    private static Engine engineOf(Context context) {\n        Engine engine = context == null ? null : context.getEngine();\n        if (engine == null) {\n            engine = Engine.current();\n        }\n        if (engine == null) {\n            throw JsErrorException.typeError(\"Promise requires an engine\");\n        }\n        return engine;\n    }\n\n    private static AsyncScope scopeOf(Engine engine) {\n        AsyncScope scope = engine.currentScope();\n        if (scope == null) {\n            throw JsErrorException.typeError(\"Promise requires an active evaluation\");\n        }\n        return scope;\n    }\n\n    static JsPromise newPromise(Context context) {\n        Engine engine = engineOf(context);\n        AsyncActivation.anyAsync = true;\n        return new JsPromise(engine, scopeOf(engine));\n    }\n","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsPromiseConstructor.java#L45-L81","documentation":"The Promise constructor needs access to a karate-js Engine (for the microtask queue/AsyncScope). engineOf resolves the engine from the current Context, then Engine.current(); if both are absent, constructing or calling Promise throws 'Promise requires an engine'.","triggerScenarios":"Evaluating JS that touches Promise outside a managed engine context — e.g. calling the Promise constructor/resolve/reject functions from a detached Context with no engine attached and no thread-local Engine.current() set.","commonSituations":"Embedding the JS engine in a host application and invoking Promise-related functions from a non-engine thread; constructing Context objects manually without binding an Engine; async/await code evaluated in a headless/embedded harness.","solutions":["Ensure the Context used to evaluate Promise code has an Engine attached (context.getEngine() != null)","Run the evaluation on the engine's thread, or set Engine.current(engine) for the duration of the call in custom threads","Create/enter the engine before constructing Promises rather than reusing bare constructors cross-thread","Route async JS through the engine's evaluation API instead of calling Promise internals directly"],"exampleFix":"// before\nContext ctx = Context.newDetached(); // no engine\nctx.eval(\"new Promise(r => r(1))\"); // TypeError: Promise requires an engine\n// after\nEngine engine = Engine.newEngine();\nContext ctx = Context.newBuilder().engine(engine).build(); // engine bound\nctx.eval(\"new Promise(r => r(1))\");","handlingStrategy":"try-catch","validationCode":"if (context == null || context.getEngine() == null) throw new IllegalStateException('Promise code needs an Engine-bound Context or Engine.current()');","typeGuard":"function hasEngine(ctx) { return ctx != null && ctx.getEngine() != null; }","tryCatchPattern":"try { return evalWithPromises(ctx, script); } catch (JsErrorException e) { if (String(e.getMessage()).contains('Promise requires an engine')) { Engine.current(engine); return evalWithPromises(ctx, script); } throw e; }","preventionTips":["Always create Promises through an engine-bound Context","Set Engine.current(engine) on custom/worker threads before evaluating async JS","In embedded hosts, keep all JS evaluation on threads where the engine is registered"],"tags":["javascript","promise","async","engine"],"backgroundTag":"missing-required-config","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"}