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

  1. Verify the receiver is a function before calling: typeof fn === 'function'.
  2. Fix the lookup/registry so the expected function is actually present.
  3. 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

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


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)