karatelabs/karate · error · ParserException
unexpected character '\u%04X' at
Error message
unexpected character '\u%04X' at %d:%d
What it means
When a character above ASCII 127 cannot start an identifier or operator, the lexer checks its Unicode category: format, control, line-separator, or paragraph-separator characters are explicitly rejected because Unicode ID_Start/ID_Continue rules make them invalid in source text. The error names the code point and lexer position. Other non-ASCII characters fall through as IDENT and fail later in the parser instead.
Solutions
- Delete and retype the region around the reported line:column to remove invisible characters.
- Strip format/control characters from the script before use (e.g. replace /[\u200B-\u200D\uFEFF\u00AD]/g in an editor or build step).
- Save the feature file as UTF-8 without BOM.
- Paste code through a plain-text editor to drop rich-text artifacts.
Example fix
// before (contains invisible U+200D between 'a' and 'r') * def name = varValue // after (retyped clean) * def name = varValue
Defensive patterns
Strategy: validation
Validate before calling
// strip invisible format/control characters before eval var clean = script.replace(/[\u200B-\u200D\uFEFF\u00AD\u2028\u2029]/g, '');
Try / catch
try {
def x = eval(script);
} catch (e) {
if (e.message && e.message.indexOf('unexpected character') >= 0) {
karate.log('invisible character detected, clean and retype: ' + e.message);
}
throw e;
} Prevention
- Paste code through a plain-text editor to drop zero-width/format characters.
- Save feature files as UTF-8 without BOM.
- Sanitize fixture strings that may carry control characters.
- On this error, delete and retype the token at the reported line:column.
When it happens
Trigger: Invisible characters pasted into embedded JS: zero-width joiner (U+200D), BOM (U+FEFF) mid-expression, soft hyphen (U+00AD), or U+2028/U+2029 line separators inside a JS expression on one line.
Common situations: Copy-pasting code from rich text editors, Slack, PDFs, or web pages that insert zero-width or directional-format characters; hidden BOM after edits; JSON fixtures carrying control characters interpolated into scripts.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- invalid unicode escape sequence in template literal
- unicode escape sequence out of range in template literal
- invalid escape sequence in template literal: \
- invalid escape sequence in template literal: \0
- invalid hex escape sequence in template literal
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/de53e08b95e0e2de.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/parser/JsLexer.java:889
}
return match('=') ? STAR_EQ : STAR;
case '%':
return match('=') ? PERCENT_EQ : PERCENT;
default:
// A non-ASCII char in a category that can never be identifier
// material or whitespace is a SyntaxError (§12.2) — e.g. U+180E
// Mongolian vowel separator (Cf; whitespace in old Unicode).
// Everything else keeps the lenient IDENT fallback: chars the
// JDK's Unicode tables don't classify yet (newer-Unicode
// ID_Start additions land as UNASSIGNED here) must still lex
// as identifiers.
if (c > 127) {
int type = Character.getType(c);
if (type == Character.FORMAT || type == Character.CONTROL
|| type == Character.LINE_SEPARATOR || type == Character.PARAGRAPH_SEPARATOR) {
throw new ParserException(String.format(
"unexpected character '\\u%04X' at %d:%d", (int) c, tokenLine + 1, tokenCol + 1));
}
}
// Unknown character - return as IDENT (will likely cause parse error)
return IDENT;
}
}
/** StringValue of a string-literal interior: escape sequences decoded to
* their characters. Shared by runtime evaluation (Interpreter) and the
* parser's {@code __proto__}-key comparison (B.3.1 counts escaped
* spellings). */
public static String unescapeStringLiteral(String s) {
if (s.indexOf('\\') == -1) {
return s; // no escapes, fast path
}
StringBuilder sb = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {View on GitHub (pinned to a22eb90246)