karatelabs/karate · error · JsErrorException

Function.prototype.bind called on non-callable

Error message

Function.prototype.bind called on non-callable

What it means

Function.prototype.bind was invoked on a value that is not a JsCallable. bindMethod reads `this` from the context and, per §20.2.3.2, requires it to be a callable function; otherwise it throws a TypeError before constructing the bound function.

Solutions

  1. Check typeof target === 'function' before calling bind().
  2. Correct the variable/property so it actually references a function.
  3. Use an arrow function closure instead of bind if you control the call site.
  4. Guard with a default: `(target || function(){}).bind(this)` when a no-op is acceptable.

Example fix

// before
var bound = maybeFn.bind(this); // TypeError if maybeFn is not a function
// after
var bound = typeof maybeFn === 'function' ? maybeFn.bind(this) : function() {};
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof target !== 'function') { throw new Error('bind target is not a function: ' + target); }

Type guard

function isBindable(v) { return v != null && typeof v.bind === 'function' && typeof v === 'function'; }

Try / catch

try { return target.bind(thisArg); } catch (e) { karate.log('bind failed on', target); return function() {}; }

Prevention

When it happens

Trigger: Calling someValue.bind(this) where someValue is undefined, null, a plain object, a number/string, or a Java-exposed object that is not a JS function; destructuring a method off an object and binding it when the lookup failed.

Common situations: Callback registration code where the callback variable was never assigned; using .bind defensively on something assumed to be a function; refactors that replaced a function-typed field with a non-function value.

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/3356b0043d935e9d. Report an issue: GitHub.

Appendix: source

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

        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");
        }
        Object boundThis = args.length > 0 ? args[0] : Terms.UNDEFINED;
        Object[] preBound = args.length > 1
                ? Arrays.copyOfRange(args, 1, args.length)
                : new Object[0];
        JsFunction bound = new JsFunction() {
            @Override
            public Object call(Context ctx, Object[] callArgs) {
                Object[] all;
                if (preBound.length == 0) {
                    all = callArgs;
                } else {
                    all = new Object[preBound.length + callArgs.length];
                    System.arraycopy(preBound, 0, all, 0, preBound.length);
                    System.arraycopy(callArgs, 0, all, preBound.length, callArgs.length);
                }
                if (ctx instanceof CoreContext cc) {
                    cc.thisObject = boundThis;

View on GitHub (pinned to a22eb90246)