karatelabs/karate · error · TypeError

Method WeakMap.prototype called on incompatible receiver

Error message

Method WeakMap.prototype called on incompatible receiver

What it means

WeakMap prototype methods (get, set, has, delete) must be invoked with a real JsWeakMap as `this`. Karate's asWeakMap() inspects context.getThisObject() and throws this TypeError when the receiver is not a JsWeakMap — for example when a method is detached and called standalone, or called on a subclass/proxy instance that isn't the engine's WeakMap class.

Solutions

  1. Bind methods before detaching: const g = wm.get.bind(wm).
  2. Always call methods on the instance: wm.get(key), not WeakMap.prototype.get.call(other, key).
  3. Ensure helper functions receive the actual WeakMap instance created in the same engine.
  4. If you need generic behavior, accept the map as a parameter and call methods on it directly.

Example fix

// before
const get = wm.get;
get(key); // incompatible receiver

// after
const get = wm.get.bind(wm);
get(key);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(m instanceof WeakMap)) throw new Error('receiver must be a WeakMap');

Type guard

function isWeakMap(x) { try { WeakMap.prototype.set.call(x, {}, 1); return true; } catch (e) { return false; } }

Try / catch

try { return wm.get(key); } catch (e) { if (String(e).indexOf('incompatible receiver') !== -1) throw new Error('use wm.get.bind(wm) before detaching methods'); throw e; }

Prevention

When it happens

Trigger: const g = wm.get; g(key) (unbound method); WeakMap.prototype.has.call(nonWeakMap, key); calling methods on an object that merely looks like a WeakMap; calling a prototype method via call/apply with the wrong this.

Common situations: Extracting methods for callbacks (forEach-style usage) without binding; mixing WeakMaps across script contexts/engines where classes differ; passing map-like mocks into helper functions.

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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsWeakMapPrototype.java:51

    static final JsWeakMapPrototype INSTANCE = new JsWeakMapPrototype();

    private JsWeakMapPrototype() {
        super(JsObjectPrototype.INSTANCE);
        install("get", 1, this::get);
        install("set", 2, this::set);
        install("has", 1, this::has);
        install("delete", 1, this::delete);
        // Spec tags WeakMap via @@toStringTag rather than a builtin class check.
        install("@@toStringTag", "WeakMap");
        installConstructor("WeakMap");
    }

    private static JsWeakMap asWeakMap(Context context) {
        Object thisObj = context.getThisObject();
        if (thisObj instanceof JsWeakMap m) {
            return m;
        }
        throw JsErrorException.typeError("Method WeakMap.prototype called on incompatible receiver");
    }

    private Object get(Context context, Object[] args) {
        return asWeakMap(context).getValue(args.length > 0 ? args[0] : Terms.UNDEFINED);
    }

    private Object set(Context context, Object[] args) {
        JsWeakMap m = asWeakMap(context);
        m.setValue(args.length > 0 ? args[0] : Terms.UNDEFINED, args.length > 1 ? args[1] : Terms.UNDEFINED);
        return m;
    }

    private Object has(Context context, Object[] args) {
        return asWeakMap(context).hasKey(args.length > 0 ? args[0] : Terms.UNDEFINED);
    }

    private Object delete(Context context, Object[] args) {
        return asWeakMap(context).deleteKey(args.length > 0 ? args[0] : Terms.UNDEFINED);

View on GitHub (pinned to a22eb90246)