{"record":{"id":"318d8678cc4895ab","repo":"karatelabs/karate","slug":"method-weakset-prototype-called-on-incompatible-receiver","errorCode":null,"errorMessage":"Method WeakSet.prototype called on incompatible receiver","messagePattern":"Method WeakSet\\.prototype called on incompatible receiver","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsWeakSetPrototype.java","lineNumber":49,"sourceCode":"class JsWeakSetPrototype extends Prototype {\n\n    static final JsWeakSetPrototype INSTANCE = new JsWeakSetPrototype();\n\n    private JsWeakSetPrototype() {\n        super(JsObjectPrototype.INSTANCE);\n        install(\"add\", 1, this::add);\n        install(\"has\", 1, this::has);\n        install(\"delete\", 1, this::delete);\n        install(\"@@toStringTag\", \"WeakSet\");\n        installConstructor(\"WeakSet\");\n    }\n\n    private static JsWeakSet asWeakSet(Context context) {\n        Object thisObj = context.getThisObject();\n        if (thisObj instanceof JsWeakSet s) {\n            return s;\n        }\n        throw JsErrorException.typeError(\"Method WeakSet.prototype called on incompatible receiver\");\n    }\n\n    private Object add(Context context, Object[] args) {\n        JsWeakSet s = asWeakSet(context);\n        s.addValue(args.length > 0 ? args[0] : Terms.UNDEFINED);\n        return s;\n    }\n\n    private Object has(Context context, Object[] args) {\n        return asWeakSet(context).has(args.length > 0 ? args[0] : Terms.UNDEFINED);\n    }\n\n    private Object delete(Context context, Object[] args) {\n        return asWeakSet(context).deleteValue(args.length > 0 ? args[0] : Terms.UNDEFINED);\n    }\n\n}\n","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsWeakSetPrototype.java#L31-L67","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Bind before detaching: const add = ws.add.bind(ws).","Call methods directly on the instance: ws.add(obj).","Pass the WeakSet instance itself as a callback: arr.forEach(fn, ws) won't help for add — use arr.forEach(v => ws.add(v)).","Verify the receiver was created via new WeakSet() in the same evaluation context."],"exampleFix":"// before\nconst add = ws.add;\n[obj1, obj2].forEach(add); // incompatible receiver (this=undefined)\n\n// after\n[obj1, obj2].forEach(o => ws.add(o));","handlingStrategy":"type-guard","validationCode":"if (!(s instanceof WeakSet)) throw new Error('receiver must be a WeakSet');","typeGuard":"function isWeakSet(x) { try { WeakSet.prototype.has.call(x, {}); return true; } catch (e) { return false; } }","tryCatchPattern":"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; }","preventionTips":["Wrap detached methods: ws.add.bind(ws)","Use arrow callbacks (v => ws.add(v)) instead of passing the method itself","Only call prototype methods with real WeakSet receivers"],"tags":["javascript","weakset","this-binding","typeerror"],"backgroundTag":"type-mismatch","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}