karatelabs/karate · error · TypeError

Method WeakSet.prototype called on incompatible receiver

Error message

Method WeakSet.prototype called on incompatible receiver

What it means

WeakSet prototype methods (add, has, delete) require `this` to be an actual JsWeakSet. Karate's asWeakSet() checks context.getThisObject() and throws this TypeError for any incompatible receiver — detached methods called with a wrong this, or non-WeakSet objects.

Solutions

  1. Bind before detaching: const add = ws.add.bind(ws).
  2. Call methods directly on the instance: ws.add(obj).
  3. Pass the WeakSet instance itself as a callback: arr.forEach(fn, ws) won't help for add — use arr.forEach(v => ws.add(v)).
  4. Verify the receiver was created via new WeakSet() in the same evaluation context.

Example fix

// before
const add = ws.add;
[obj1, obj2].forEach(add); // incompatible receiver (this=undefined)

// after
[obj1, obj2].forEach(o => ws.add(o));
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(s instanceof WeakSet)) throw new Error('receiver must be a WeakSet');

Type guard

function isWeakSet(x) { try { WeakSet.prototype.has.call(x, {}); return true; } catch (e) { return false; } }

Try / catch

try { ws.add(v); } catch (e) { if (String(e).indexOf('incompatible receiver') !== -1) throw new Error('bind ws.add before using it as a callback'); throw e; }

Prevention

When it happens

Trigger: const a = ws.add; a(obj) (unbound); WeakSet.prototype.has.call(fakeSet, obj); invoking prototype methods on plain objects or objects from a different engine context.

Common situations: Passing ws.add as a callback (e.g. to forEach) without binding; helper utilities expecting duck-typed sets; cross-context object mixing in embedded engines.

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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsWeakSetPrototype.java:49

class JsWeakSetPrototype extends Prototype {

    static final JsWeakSetPrototype INSTANCE = new JsWeakSetPrototype();

    private JsWeakSetPrototype() {
        super(JsObjectPrototype.INSTANCE);
        install("add", 1, this::add);
        install("has", 1, this::has);
        install("delete", 1, this::delete);
        install("@@toStringTag", "WeakSet");
        installConstructor("WeakSet");
    }

    private static JsWeakSet asWeakSet(Context context) {
        Object thisObj = context.getThisObject();
        if (thisObj instanceof JsWeakSet s) {
            return s;
        }
        throw JsErrorException.typeError("Method WeakSet.prototype called on incompatible receiver");
    }

    private Object add(Context context, Object[] args) {
        JsWeakSet s = asWeakSet(context);
        s.addValue(args.length > 0 ? args[0] : Terms.UNDEFINED);
        return s;
    }

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

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

}

View on GitHub (pinned to a22eb90246)