karatelabs/karate · error · JsErrorException

Promise resolve is not a function

Error message

Promise resolve is not a function

What it means

The spec's PerformPromiseAll reads the `resolve` static off the constructor and requires it to be callable before iterating the input. Karate reads `resolve` once via `getMember` and throws this TypeError when the receiver's `resolve` is missing or not a JsCallable — i.e. the combinator's `this` constructor doesn't provide a usable `resolve`.

Solutions

  1. Restore `Promise.resolve` to a function (reload/refresh the engine context if it was patched).
  2. When rebinding combinators, pass a class that defines a callable static `resolve`.
  3. Guard: `if (typeof Promise.resolve !== 'function') throw ...` before using combinators.

Example fix

// before (test stub)
Promise.resolve = (v) => v; // breaks subclass generics? no — returns value, not thenable... worse: assigned non-callable
// after
Promise.resolve = (v) => new Promise((res) => res(v));
Defensive patterns

Strategy: validation

Validate before calling

function combinatorReady(ctor) {
  const c = ctor || Promise;
  return typeof c === 'function' && typeof c.resolve === 'function';
}

Type guard

function hasCallableResolve(ctor) { return ctor != null && typeof ctor.resolve === 'function'; }

Try / catch

try { return Receiver.all(iterable); } catch (e) { if (e instanceof TypeError && /resolve is not a function/.test(e.message)) return Promise.all(iterable); throw e; }

Prevention

When it happens

Trigger: `Promise.all.call(SomeClass, iterable)` where SomeClass has no static `resolve` or a non-function `resolve`; deleting/overwriting `Promise.resolve` with a non-function before calling a combinator.

Common situations: Stubbing Promise.resolve in tests with a plain value; half-implemented Promise subclasses; config code that overwrites Promise members.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

     */
    private List<JsPromise> collect(Context context, Object[] args, JsPromise result) {
        Engine engine = engineOf(context);
        AsyncScope scope = scopeOf(engine);
        AsyncActivation.anyAsync = true;
        // NewPromiseCapability(C) rejects a non-constructor `this` with a
        // synchronous TypeError, ahead of everything the IfAbruptRejectPromise
        // steps below cover. Outside the try for exactly that reason.
        ObjectLike receiver = constructorOf(context);
        Object iterable = AsyncSupport.arg(args, 0);
        List<JsPromise> promises = new ArrayList<>();
        JsIterator iter = null;
        try {
            // GetPromiseResolve: read `resolve` off the constructor exactly once,
            // before iteration begins.
            Object resolveFn = receiver.getMember("resolve", receiver, coreOf(context));
            checkAbrupt(context);
            if (!(resolveFn instanceof JsCallable resolveCallable)) {
                throw JsErrorException.typeError("Promise resolve is not a function");
            }
            boolean intrinsic = receiver == this
                    && resolveFn instanceof JsBuiltinMethod m && m.delegate() == resolveDelegate;
            iter = IterUtils.getIterator(iterable, context);
            checkAbrupt(context);
            while (iter.hasNext()) {
                Object item = iter.next();
                checkAbrupt(context);
                Object next = intrinsic
                        ? resolveStatic(context, new Object[]{item})
                        : callWithThis(context, resolveCallable, receiver, new Object[]{item});
                checkAbrupt(context);
                promises.add(asPromise(context, engine, scope, next, intrinsic));
            }
            // A throw from next() / done / value marks the iterator exhausted and
            // ends the loop quietly — the pending flag is the real completion.
            checkAbrupt(context);
            return promises;

View on GitHub (pinned to a22eb90246)