karatelabs/karate · error · TypeError

Method Set.prototype called on incompatible receiver

Error message

Method Set.prototype called on incompatible receiver

What it means

A Set.prototype method (add, has, delete, clear, etc.) was invoked with a `this` that is not an actual Set instance. The engine resolves the receiver with asSet() and throws a TypeError when it is anything else.

Solutions

  1. Call the method on a real Set instance created with new Set().
  2. Use .call/.apply only with a genuine Set as the first argument.
  3. Bind the method once and reuse the bound instance: const has = mySet.has.bind(mySet).
  4. Validate with instanceof Set before invoking its methods.

Example fix

// before
const has = mySet.has;
has(value);
// after
const has = mySet.has.bind(mySet);
has(value);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(s instanceof Set)) throw new TypeError('expected a Set');

Type guard

function isSet(v) { return v instanceof Set; }

Try / catch

try { return mySet.has(value); } catch (e) { if (String(e).includes('incompatible receiver')) { const s = new Set(); return false; } throw e; }

Prevention

When it happens

Trigger: Extracting a method and calling it unbound: const h = new Set().has; h(...); or Set.prototype.add.call(nonSet, v); or calling .has on undefined/null due to a chained lookup that silently returned undefined.

Common situations: Method borrowing from prototypes; passing a plain object or Map where a Set was expected; optional-chaining chains that skipped construction (e.g. maybeSet?.has(x) where maybeSet is not a Set).

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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsSetPrototype.java:73

        // to integer, validate callability). Result-bearing methods build a
        // fresh JsSet by populating elements directly (spec bypasses
        // Set.prototype.add — verified by add-not-called.js test262).
        install("union", 1, this::union);
        install("intersection", 1, this::intersection);
        install("difference", 1, this::difference);
        install("symmetricDifference", 1, this::symmetricDifference);
        install("isSubsetOf", 1, this::isSubsetOf);
        install("isSupersetOf", 1, this::isSupersetOf);
        install("isDisjointFrom", 1, this::isDisjointFrom);
        installConstructor("Set");
    }

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

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

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

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

    private Object clear(Context context, Object[] args) {
        asSet(context).clearAll();

View on GitHub (pinned to a22eb90246)