{"record":{"id":"610554e4cc1d6109","repo":"karatelabs/karate","slug":"regexp-prototype-called-on-incompatible-receiver","errorCode":null,"errorMessage":"RegExp.prototype. called on incompatible receiver","messagePattern":"RegExp\\.prototype\\. called on incompatible receiver","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/JsRegexPrototype.java","lineNumber":90,"sourceCode":"    // via {@code userProps}).\n    private void installFlagAccessor(String name, Object protoSentinel,\n                                      Function<JsRegex, Object> extractor) {\n        JsCallable lambda = (ctx, args) -> {\n            Object thisObj = ctx.getThisObject();\n            if (thisObj == this) return protoSentinel;\n            if (thisObj instanceof JsRegex r) return extractor.apply(r);\n            throw JsErrorException.typeError(\"get RegExp.prototype.\" + name + \" called on incompatible receiver\");\n        };\n        JsBuiltinMethod getter = new JsBuiltinMethod(\"get \" + name, 0, lambda);\n        installAccessor(name, getter, null, ACCESSOR_ATTRS);\n    }\n\n    // Spec preamble for test / exec — RegExp objects are required (no ToString\n    // coercion of `this`); the search string is ToString-coerced.\n    private static JsRegex requireRegex(Context context, String methodName) {\n        Object thisObj = context.getThisObject();\n        if (thisObj instanceof JsRegex r) return r;\n        throw JsErrorException.typeError(\"RegExp.prototype.\" + methodName + \" called on incompatible receiver\");\n    }\n\n    private static String argString(Object[] args, Context context) {\n        Object arg = args.length > 0 ? args[0] : Terms.UNDEFINED;\n        if (arg instanceof String s) return s;\n        if (arg instanceof JsString js) return js.text;\n        return Terms.toStringCoerce(arg, context instanceof CoreContext cc ? cc : null);\n    }\n\n    // Instance methods\n\n    private Object test(Context context, Object[] args) {\n        return requireRegex(context, \"test\").test(argString(args, context));\n    }\n\n    private Object exec(Context context, Object[] args) {\n        return requireRegex(context, \"exec\").exec(argString(args, context));\n    }","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/JsRegexPrototype.java#L72-L108","documentation":"RegExp.prototype.test and RegExp.prototype.exec perform a strict brand check: `this` must be an actual JsRegex instance — no ToString coercion or duck typing. If thisObj is not a JsRegex, a TypeError 'RegExp.prototype.<methodName> called on incompatible receiver' is thrown, per the spec's RequireInternalSlot-style preamble.","triggerScenarios":"const t = re.test; t('str') (this becomes undefined); RegExp.prototype.test.call({}, 'x'); calling test/exec on a plain object or a string (e.g. 'abc'.test(...) style mistakes); applying the methods to regex-like data from another source.","commonSituations":"Extracting test/exec as callbacks (arr.map(re.test)) which loses `this`; typos like someString.exec(pattern); passing mock/duck-typed regex objects in tests; migrating code from libraries whose regex methods coerced `this`.","solutions":["Call the method bound to a real regex: re.test(str) or re.test.bind(re) when passing as a callback","Ensure the receiver is an actual RegExp instance, not a string or plain object","For one-off checks on strings, use the free forms str.match(re), str.search(re), or re.test(...)/re.exec(...) on a constructed RegExp"],"exampleFix":"// before\n['a1','b2'].map(re.test); // this lost -> TypeError\n// after\n['a1','b2'].map(s => re.test(s)); // or re.test.bind(re)","handlingStrategy":"type-guard","validationCode":"if (!(re instanceof RegExp)) throw new Error('test/exec receiver must be a RegExp, got: ' + typeof re);\nreturn re.test(str);","typeGuard":"const isRegex = v => v instanceof RegExp;\nconst matches = (v, s) => isRegex(v) ? v.test(s) : new RegExp(String(v)).test(s);","tryCatchPattern":"try {\n  return re.test(input);\n} catch (e) {\n  if (String(e.message).includes('incompatible receiver')) {\n    throw new Error('test/exec called with lost `this`; bind the regex');\n  }\n  throw e;\n}","preventionTips":["Never detach test/exec from their regex (avoid arr.map(re.test)); use an arrow wrapper or .bind(re)","Do not call test/exec on strings or plain objects; use str.match/str.search instead","Ensure mocks and regex-like values from other libraries are real RegExp instances","Type-check regex receivers in helpers that accept 'anything regex-shaped'"],"tags":["javascript","regexp","typeerror","this-binding"],"backgroundTag":"invalid-argument-value","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"}