{"record":{"id":"c6673298eba8bb4b","repo":"karatelabs/karate","slug":"set-like-object-s-size-is-negative","errorCode":null,"errorMessage":"Set-like object's size is negative","messagePattern":"Set-like object's size is negative","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsSetPrototype.java","lineNumber":177,"sourceCode":"        if (!(other instanceof ObjectLike obj)) {\n            throw JsErrorException.typeError(\"Set.prototype method called with non-object\");\n        }\n        CoreContext cc = context instanceof CoreContext c ? c : null;\n        Object rawSize = obj.getMember(\"size\", obj, cc);\n        Number numSize = Terms.toNumberCoerce(rawSize, cc);\n        double d = numSize.doubleValue();\n        if (Double.isNaN(d)) {\n            throw JsErrorException.typeError(\"Set-like object's size is not a number\");\n        }\n        // ToIntegerOrInfinity, then RangeError on negative — spec step 7.\n        long intSize;\n        if (Double.isInfinite(d)) {\n            intSize = d > 0 ? Long.MAX_VALUE : Long.MIN_VALUE;\n        } else {\n            intSize = (long) d;\n        }\n        if (intSize < 0) {\n            throw JsErrorException.rangeError(\"Set-like object's size is negative\");\n        }\n        Object hasFn = obj.getMember(\"has\", obj, cc);\n        if (!(hasFn instanceof JsCallable has)) {\n            throw JsErrorException.typeError(\"Set-like object's 'has' is not callable\");\n        }\n        Object keysFn = obj.getMember(\"keys\", obj, cc);\n        if (!(keysFn instanceof JsCallable keys)) {\n            throw JsErrorException.typeError(\"Set-like object's 'keys' is not callable\");\n        }\n        return new SetRecord(obj, intSize, has, keys);\n    }\n\n    private static JsIterator keysIter(SetRecord rec, Context ctx) {\n        return IterUtils.iteratorFromCallable(rec.keys, rec.setObj, ctx);\n    }\n\n    /** Spec normalize: -0 → +0 on values pulled from a foreign keys() iteration. */\n    private static Object normalize(Object v) {","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsSetPrototype.java#L159-L195","documentation":"SetRecord validation per the ES spec (ToIntegerOrInfinity then RangeError): a Set-like object's 'size' coerced to a negative number, which is invalid for set operations. Fix the object so its 'size' is a non-negative number.","triggerScenarios":"set.difference({ size: -1, has: fn, keys: fn }); or a Set-like whose size getter computes a negative count.","commonSituations":"Custom Set-like wrappers computing size with an off-by-one or subtracting counts incorrectly; deserialized objects with negative size sentinels.","solutions":["Fix the size computation so it is non-negative, or clamp: Math.max(0, size).","Use a real Set as the other argument.","Validate other.size >= 0 before calling."],"exampleFix":"// before\nconst like = { size: computedSize, has, keys };\nmySet.difference(like);\n// after\nconst like = { size: Math.max(0, computedSize), has, keys };\nmySet.difference(like);","handlingStrategy":"validation","validationCode":"if (Number(other?.size) < 0) throw new RangeError('size must be >= 0');","typeGuard":"function hasNonNegativeSize(v) { return v !== null && typeof v === 'object' && Number.isFinite(Number(v.size)) && Number(v.size) >= 0; }","tryCatchPattern":"try { return mySet.difference(other); } catch (e) { if (String(e).includes('size is negative')) return mySet.difference(new Set()); throw e; }","preventionTips":["Clamp computed sizes with Math.max(0, size).","Fix off-by-one or subtraction bugs in size getters.","Add assertions that size >= 0 when building Set-likes."],"tags":["javascript","set","range-error"],"backgroundTag":"value-out-of-range","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}