karatelabs/karate · error · JsErrorException

Promise requires an active evaluation

Error message

Promise requires an active evaluation

What it means

Karate's JS engine exposes Promise via `scopeOf`, which fetches the engine's current AsyncScope. Promises only make sense while a script evaluation with an async scope is running (microtask queue attached). If `engine.currentScope()` returns null — e.g. Promise is touched outside any evaluation, from another thread, or after evaluation finished — the engine throws this TypeError instead of silently misbehaving.

Solutions

  1. Ensure Promise usage happens inside a live script evaluation; don't cache or call Promise-related values after eval returns.
  2. If embedding, run Promise-dependent code on the engine's evaluation thread (or via the engine's async execution entry points) rather than a custom thread.
  3. Check that no code path nulls out or completes the engine's current scope before the constructor is invoked.

Example fix

// before: host thread invokes JS directly
executor.submit(() -> engine.eval("new Promise(r => r(1))"));
// after: run through the engine's own evaluation/async path
engine.submit("new Promise(r => r(1))"); // engine manages scope
Defensive patterns

Strategy: type-guard

Validate before calling

// host-side (Java): only evaluate Promise code inside a live evaluation
if (engine.currentScope() == null) {
    throw new IllegalStateException("Promise used outside active evaluation");
}

Type guard

function hasActiveScope(engine) { return engine && typeof engine.currentScope === 'function' && engine.currentScope() != null; }

Try / catch

try { return evalUserScript(); } catch (e) { if (String(e).includes('Promise requires an active evaluation')) { /* re-run on evaluation thread */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling `new Promise(...)` or `Promise.resolve()/reject()` when no AsyncScope is active: accessing the Promise global outside `eval()` on the engine, invoking the constructor from a non-script thread, or calling it after the evaluation has completed.

Common situations: Embedding karate-js in a host app and invoking JS callbacks on a plain Java thread without pushing a scope; using Promise inside a synchronous one-shot eval that tears down its scope before the constructor runs; racing two engine usages across threads.

Related errors


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

Appendix: source

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

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

    @Override
    public Object call(Context context, Object[] args) {
        CallInfo callInfo = context.getCallInfo();
        if (callInfo == null || !callInfo.constructor) {
            throw JsErrorException.typeError("Promise constructor cannot be invoked without 'new'");
        }
        Object executor = AsyncSupport.arg(args, 0);
        if (!(executor instanceof JsCallable callable)) {

View on GitHub (pinned to a22eb90246)