karatelabs/karate · error · TypeError
RegExp.escape called on non-string
Error message
RegExp.escape called on non-string
What it means
RegExp.escape (ES2025) requires a String argument per spec §22.2.7.1 — it does not coerce. Karate throws a TypeError 'RegExp.escape called on non-string' when the first argument is missing, undefined, or any non-string value (number, object, etc.).
Solutions
- Convert explicitly first: RegExp.escape(String(value))
- Guard with typeof value === 'string' before calling, and handle non-strings separately
- Provide a default: RegExp.escape(value ?? '')
Example fix
// before const safe = RegExp.escape(userInput); // may be a number // after const safe = typeof userInput === 'string' ? RegExp.escape(userInput) : '';
Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof v !== 'string') throw new Error('RegExp.escape requires a string, got: ' + typeof v);
const safe = RegExp.escape(v); Type guard
const isStr = v => typeof v === 'string'; const safeEscape = v => isStr(v) ? RegExp.escape(v) : RegExp.escape(String(v));
Try / catch
try {
return RegExp.escape(value);
} catch (e) {
if (String(e.message).includes('non-string')) {
return RegExp.escape(String(value));
}
throw e;
} Prevention
- Coerce with String(value) before escaping when input type is uncertain
- Handle undefined captures/nulls from match results before escaping
- Never rely on implicit ToString coercion for spec-strict builtins
- Validate user-supplied values at the boundary before regex construction
When it happens
Trigger: RegExp.escape(); RegExp.escape(42); RegExp.escape(userValue) where userValue is a number or null; relying on implicit ToString coercion that the spec forbids.
Common situations: Escaping user input for safe interpolation into a RegExp before checking its type; passing match-array captures (which can be undefined) or numbers from form/API data directly to RegExp.escape.
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
- get RegExp.prototype. called on incompatible receiver
- RegExp.prototype. called on incompatible receiver
- Cannot set property ' ' which has only a getter
- assignment to constant
- assignment to constant
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/7a82df688c282e73.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsRegexConstructor.java:63
}
@Override
public Object call(Context context, Object... args) {
if (args.length == 0) {
return new JsRegex();
}
String pattern = args[0].toString();
String flags = args.length > 1 ? args[1].toString() : "";
return new JsRegex(pattern, flags);
}
// RegExp.escape (ES2025). Spec §22.2.7.1: TypeError on non-String input;
// walks code points, prefixes leading digit/letter with \x##, otherwise
// delegates each code point to EncodeForRegExpEscape.
private Object escape(Object[] args) {
Object s = args.length > 0 ? args[0] : Terms.UNDEFINED;
if (!(s instanceof String str)) {
throw JsErrorException.typeError("RegExp.escape called on non-string");
}
StringBuilder out = new StringBuilder(str.length() + 8);
for (int i = 0; i < str.length(); ) {
int cp = str.codePointAt(i);
if (out.length() == 0 && isAsciiDigitOrLetter(cp)) {
out.append("\\x").append(toHexLowerPad(cp, 2));
} else {
encodeForRegExpEscape(out, cp);
}
i += Character.charCount(cp);
}
return out.toString();
}
private static boolean isAsciiDigitOrLetter(int cp) {
return (cp >= '0' && cp <= '9') || (cp >= 'A' && cp <= 'Z') || (cp >= 'a' && cp <= 'z');
}
View on GitHub (pinned to a22eb90246)