karatelabs/karate · error · JsErrorException
Function.prototype.call called on non-callable
Error message
Function.prototype.call called on non-callable
What it means
Function.prototype.call invokes its receiver as a callable after rebinding `this`. If the receiver is not callable (undefined, null, a plain object, etc.), Karate throws this TypeError, matching spec §20.3.4.1 step 2 (Call on non-callable).
Solutions
- Verify the receiver is a function before calling: typeof fn === 'function'.
- Fix the lookup/registry so the expected function is actually present.
- Provide a default no-op: (fn || (() => {})).call(thisArg, ...).
Example fix
// before handlers[type].call(ctx, ev); // TypeError when handlers[type] is undefined // after if (typeof handlers[type] === 'function') handlers[type].call(ctx, ev);
Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof fn !== 'function') throw new Error('expected a callable, got: ' + typeof fn); Type guard
function isCallable(v) { return typeof v === 'function'; } Try / catch
try { return fn.call(ctx, arg); } catch (e) { if (e instanceof TypeError && /non-callable/.test(e.message)) return noOpResult; throw e; } Prevention
- Check typeof before invoking looked-up or injected callbacks.
- Provide default no-op functions for optional hooks.
- Validate registry/plugin entries at registration time.
- Avoid overwriting function-valued properties with non-functions.
When it happens
Trigger: Function.prototype.call.call({}, obj), calling a method reference whose target was replaced by a non-function, invoking fn.call where fn resolved to undefined from a config or lookup map.
Common situations: Dependency-injected callbacks that are missing (undefined) at call time, plugin registries where an entry was overwritten with a non-function, destructured functions from objects that lack the key.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- AggregateError requires an iterable of errors
- Array.from requires an iterable or array-like object, not
- Array.prototype.* called on null or undefined
- BigInt.prototype method called on non-BigInt
- BigInts have no unsigned right shift, use >> instead
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/aef0e61a4f69b144.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsFunctionPrototype.java:89
this.args = list;
} else {
Object first = list.getFirst();
if (first instanceof List) {
this.args = ((List<Object>) first);
} else {
this.args = new ArrayList<>();
}
}
} else {
this.args = list;
}
}
}
private Object callMethod(Context context, Object[] args) {
JsCallable callable = asCallable(context);
if (callable == null) {
throw JsErrorException.typeError("Function.prototype.call called on non-callable");
}
ThisArgs thisArgs = new ThisArgs(args, false);
if (context instanceof CoreContext cc) {
cc.thisObject = bindForCall(callable, thisArgs.thisObject, cc);
}
return callable.call(context, thisArgs.args.toArray(new Object[0]));
}
// Spec OrdinaryCallBindThis (§9.2.1.2): the null/undefined → globalThis
// substitution applies to sloppy-mode user-defined functions only.
// Built-in methods and strict-mode user fns see the raw thisArg —
// required for e.g. Object.prototype.toString.call(null) returning
// "[object Null]" and for RequireObjectCoercible-gated built-ins to throw
// TypeError on null/undefined receivers.
private static Object bindForCall(JsCallable callable, Object thisObject, CoreContext cc) {
if (callable instanceof JsBuiltinMethod) {
return thisObject;
}View on GitHub (pinned to a22eb90246)