karatelabs/karate · error · JsErrorException
Promise resolver is not a function
Error message
Promise resolver is not a function
What it means
`new Promise(executor)` requires the executor to be a function with `(resolve, reject)` parameters. When `AsyncSupport.arg(args, 0)` is anything other than a JsCallable (undefined, a value, a non-callable object), the engine throws this TypeError, matching the spec's IsCallable check.
Solutions
- Pass an executor function: `new Promise((resolve, reject) => ...)`.
- Guard the argument before constructing: `if (typeof executor !== 'function') throw ...`.
- Log or inspect the value if it should be a function — a failed definition above often leaves it undefined.
Example fix
// before
const p = new Promise(config.executor); // executor is a plain object here
// after
if (typeof config.executor === 'function') {
const p = new Promise(config.executor);
} Defensive patterns
Strategy: validation
Validate before calling
function safeNewPromise(executor) {
if (typeof executor !== 'function') throw new TypeError('Promise executor must be a function');
return new Promise(executor);
} Type guard
function isCallable(v) { return typeof v === 'function'; } Try / catch
try { const p = new Promise(executor); } catch (e) { if (e instanceof TypeError && /resolver is not a function/.test(e.message)) executor = defaultExecutor; throw e; } Prevention
- Always inline the executor: `new Promise((resolve, reject) => ...)`.
- Check upstream definitions when passing a function by reference.
- Use an editor snippet/template for Promise construction.
When it happens
Trigger: `new Promise()` with no argument; `new Promise(42)` or `new Promise({})`; passing a variable that was expected to be a function but is undefined due to a typo or earlier failure.
Common situations: Typos in callback names; forgetting to pass the executor during a refactor; dynamic executors loaded from data that turned out to be strings/values, not functions.
Related errors
- setTimeout:
- <JS rejection reason>
- Promise requires an engine
- Promise requires an active evaluation
- Promise constructor cannot be invoked without 'new'
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/b8cd42a7d0c8504f.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsPromiseConstructor.java:90
}
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)) {
throw JsErrorException.typeError("Promise resolver is not a function");
}
JsPromise promise = newPromise(context);
AtomicBoolean claimed = new AtomicBoolean();
JsCallable resolveFn = (ctx, a) -> {
if (claimed.compareAndSet(false, true)) {
AsyncSupport.settleFromCallback(promise, AsyncSupport.arg(a, 0), false);
}
return Terms.UNDEFINED;
};
JsCallable rejectFn = (ctx, a) -> {
if (claimed.compareAndSet(false, true)) {
AsyncSupport.settleFromCallback(promise, AsyncSupport.arg(a, 0), true);
}
return Terms.UNDEFINED;
};
AsyncSupport.Completion outcome = AsyncSupport.invoke(
promise.engine, callable, new Object[]{resolveFn, rejectFn}, null);
if (outcome.threw() && claimed.compareAndSet(false, true)) {View on GitHub (pinned to a22eb90246)