karatelabs/karate · error · JsErrorException

Function.prototype.apply called on non-callable

Error message

Function.prototype.apply called on non-callable

What it means

Function.prototype.apply was invoked on a value that is not a callable (function). Karate's JS engine implements Function.prototype.apply in JsFunctionPrototype.applyMethod, and per the ECMAScript spec it first coerces `this` to a callable; if that coercion fails (asCallable returns null) it throws a TypeError instead of failing later inside the interpreter.

Solutions

  1. Print/inspect the value before calling apply and confirm it is a function (typeof fn === 'function').
  2. Fix the reference so it points at the actual function instead of a call result or property lookup that returned undefined.
  3. Use call() or spread (...) syntax instead if you do not need the apply argument-array semantics.
  4. Wrap the invocation in try/catch if the callable is genuinely optional at runtime.

Example fix

// before
var handler = config.handlers[name];
handler.apply(null, args); // handler may be undefined
// after
var handler = config.handlers[name];
if (typeof handler === 'function') {
  handler.apply(null, args);
} else {
  karate.log('no handler for', name);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof fn !== 'function') { throw new Error('expected callable, got: ' + fn); }

Type guard

function isCallable(v) { return typeof v === 'function'; }

Try / catch

try { fn.apply(thisArg, args); } catch (e) { if (String(e).indexOf('non-callable') !== -1) { karate.log('not a function:', fn); } else { throw e; } }

Prevention

When it happens

Trigger: Calling fn.apply(...) where `fn` is undefined, null, a plain object, a primitive, or a non-function value that reached the Function prototype (e.g. a method borrowed from the wrong object, or a typo like `myfunc.aply` resolving through a proxy).

Common situations: Refactoring code where a variable that used to hold a function now holds its result; calling .apply on a Java-side value exposed to JS that is not wrapped as a JsCallable; duck-typed code assuming an object has a method that is actually missing.

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


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsFunctionPrototype.java:115

    // 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;
        }
        boolean strict = callable instanceof JsFunctionNode jfn && jfn.strict;
        return Interpreter.bindThisForCall(thisObject, cc, strict);
    }

    private Object applyMethod(Context context, Object[] args) {
        JsCallable callable = asCallable(context);
        if (callable == null) {
            throw JsErrorException.typeError("Function.prototype.apply called on non-callable");
        }
        ThisArgs thisArgs = new ThisArgs(args, true);
        if (context instanceof CoreContext cc) {
            cc.thisObject = bindForCall(callable, thisArgs.thisObject, cc);
        }
        return callable.call(context, thisArgs.args.toArray(new Object[0]));
    }

    // Spec: Function.prototype.bind(thisArg, ...preBound) returns a new callable
    // that, when invoked, calls the target with `this` set to thisArg and
    // arguments = preBound concat actualArgs. Pre-bound args win in order.
    // Per §20.2.3.2 the bound function's `length` is
    // max(0, target.length - preBound.length).
    private Object bindMethod(Context context, Object[] args) {
        Object thisObj = context.getThisObject();
        if (!(thisObj instanceof JsCallable target)) {
            throw JsErrorException.typeError("Function.prototype.bind called on non-callable");
        }

View on GitHub (pinned to a22eb90246)