karatelabs/karate · error · TypeError
get RegExp.prototype. called on incompatible receiver
Error message
get RegExp.prototype. called on incompatible receiver
What it means
Flag getters like get RegExp.prototype.global are installed as accessors that accept only two receivers: the prototype object itself (returning a spec-defined sentinel like undefined) and actual JsRegex instances. For any other `this` (plain object, undefined in strict mode, a foreign regex-like object), a TypeError 'get RegExp.prototype.<flag> called on incompatible receiver' is thrown, matching spec-brand-check behavior for these getters.
Solutions
- Only read flags directly on real RegExp instances: re.global
- If using getter.call(thisObj), ensure thisObj is an actual RegExp, or pass the prototype for the sentinel path
- Duck-typed/mocked regexes must be real RegExp instances, or read flags via re.flags (string) on genuine regexes only
Example fix
// before const global = Object.getOwnPropertyDescriptor(RegExp.prototype, 'global').get.call(fakeRegex); // after const global = realRegex instanceof RegExp ? realRegex.global : false;
Defensive patterns
Strategy: type-guard
Validate before calling
function getFlag(re, flag) {
if (!(re instanceof RegExp)) throw new Error('flag getter needs a real RegExp: ' + flag);
return Object.getOwnPropertyDescriptor(RegExp.prototype, flag).get.call(re);
} Type guard
const isRealRegex = v => v instanceof RegExp; const flagOf = (re, f) => isRealRegex(re) ? re[f] : undefined;
Try / catch
try {
return flagGetter.call(thisObj);
} catch (e) {
if (String(e.message).includes('incompatible receiver')) {
throw new Error('flag getter invoked on non-RegExp receiver');
}
throw e;
} Prevention
- Read flags directly on real RegExp instances (re.global) instead of extracting getters
- Ensure getter.call/apply receivers are genuine RegExp objects
- Replace duck-typed mock regexes in tests with real RegExp instances
- Remember these getters brand-check; they do not coerce or duck-type
When it happens
Trigger: Calling RegExp.prototype.global.call({}) or .apply(nonRegex) to read a flag off a fake regex object; destructuring the getter and invoking it with the wrong this; using a regex value that came from a different engine realm/wrapper and is not a JsRegex.
Common situations: Generic 'is this regex global?' helpers that apply flag getters to arbitrary values; duck-typed mock regexes in tests; `this` lost to undefined because a getter was extracted and called bare (e.g. const g = re.global.bind semantics misunderstood).
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Method Generator.prototype called on incompatible receiver
- Method Map.prototype called on incompatible receiver
- Number.prototype method called on incompatible receiver
- RegExp.escape called on non-string
- RegExp.prototype. called on incompatible receiver
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/43fdcdd3c52a8b8b.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsRegexPrototype.java:79
installFlagAccessor("dotAll", Terms.UNDEFINED, r -> r.flags.contains("s"));
installFlagAccessor("sticky", Terms.UNDEFINED, r -> r.flags.contains("y"));
installFlagAccessor("unicode", Terms.UNDEFINED, r -> r.flags.contains("u"));
installConstructor("RegExp");
}
// Spec §22.2.6.4 etc. shared shape: TypeError on non-object receiver,
// sentinel on the prototype itself, extractor on a real JsRegex. Routes
// through {@link Prototype#installAccessor} so the descriptor lives in
// {@code builtins} and survives per-Engine reset (user-defined
// accessors via {@code Object.defineProperty} would still shadow these
// via {@code userProps}).
private void installFlagAccessor(String name, Object protoSentinel,
Function<JsRegex, Object> extractor) {
JsCallable lambda = (ctx, args) -> {
Object thisObj = ctx.getThisObject();
if (thisObj == this) return protoSentinel;
if (thisObj instanceof JsRegex r) return extractor.apply(r);
throw JsErrorException.typeError("get RegExp.prototype." + name + " called on incompatible receiver");
};
JsBuiltinMethod getter = new JsBuiltinMethod("get " + name, 0, lambda);
installAccessor(name, getter, null, ACCESSOR_ATTRS);
}
// Spec preamble for test / exec — RegExp objects are required (no ToString
// coercion of `this`); the search string is ToString-coerced.
private static JsRegex requireRegex(Context context, String methodName) {
Object thisObj = context.getThisObject();
if (thisObj instanceof JsRegex r) return r;
throw JsErrorException.typeError("RegExp.prototype." + methodName + " called on incompatible receiver");
}
private static String argString(Object[] args, Context context) {
Object arg = args.length > 0 ? args[0] : Terms.UNDEFINED;
if (arg instanceof String s) return s;
if (arg instanceof JsString js) return js.text;
return Terms.toStringCoerce(arg, context instanceof CoreContext cc ? cc : null);View on GitHub (pinned to a22eb90246)