karatelabs/karate · error · JsErrorException

Promise requires an engine

Error message

Promise requires an engine

What it means

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'.

Solutions

  1. Ensure the Context used to evaluate Promise code has an Engine attached (context.getEngine() != null)
  2. Run the evaluation on the engine's thread, or set Engine.current(engine) for the duration of the call in custom threads
  3. Create/enter the engine before constructing Promises rather than reusing bare constructors cross-thread
  4. Route async JS through the engine's evaluation API instead of calling Promise internals directly

Example fix

// before
Context ctx = Context.newDetached(); // no engine
ctx.eval("new Promise(r => r(1))"); // TypeError: Promise requires an engine
// after
Engine engine = Engine.newEngine();
Context ctx = Context.newBuilder().engine(engine).build(); // engine bound
ctx.eval("new Promise(r => r(1))");
Defensive patterns

Strategy: try-catch

Validate before calling

if (context == null || context.getEngine() == null) throw new IllegalStateException('Promise code needs an Engine-bound Context or Engine.current()');

Type guard

function hasEngine(ctx) { return ctx != null && ctx.getEngine() != null; }

Try / catch

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/241d019a51683e30. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsPromiseConstructor.java:63

    JsPromiseConstructor() {
        this.name = "Promise";
        this.length = 1;
        defineOwn("prototype", JsPromisePrototype.INSTANCE, PropertySlot.INTRINSIC);
        defineOwn("resolve", new JsBuiltinMethod("resolve", 1, resolveDelegate), METHOD_ATTRS);
        defineOwn("reject", new JsBuiltinMethod("reject", 1, (JsCallable) this::rejectStatic), METHOD_ATTRS);
        defineOwn("all", new JsBuiltinMethod("all", 1, (JsCallable) this::all), METHOD_ATTRS);
        defineOwn("allSettled", new JsBuiltinMethod("allSettled", 1, (JsCallable) this::allSettled), METHOD_ATTRS);
        defineOwn("race", new JsBuiltinMethod("race", 1, (JsCallable) this::race), METHOD_ATTRS);
        defineOwn("any", new JsBuiltinMethod("any", 1, (JsCallable) this::any), METHOD_ATTRS);
    }

    private static Engine engineOf(Context context) {
        Engine engine = context == null ? null : context.getEngine();
        if (engine == null) {
            engine = Engine.current();
        }
        if (engine == null) {
            throw JsErrorException.typeError("Promise requires an engine");
        }
        return engine;
    }

    private static AsyncScope scopeOf(Engine engine) {
        AsyncScope scope = engine.currentScope();
        if (scope == null) {
            throw JsErrorException.typeError("Promise requires an active evaluation");
        }
        return scope;
    }

    static JsPromise newPromise(Context context) {
        Engine engine = engineOf(context);
        AsyncActivation.anyAsync = true;
        return new JsPromise(engine, scopeOf(engine));
    }

View on GitHub (pinned to a22eb90246)