karatelabs/karate · error · JsErrorException
unexpected private name
Error message
unexpected private name ${node.getText()} What it means
Karate's parser produces PRIVATE_NAME_EXPR nodes for `#name` private-class-field syntax, but a normal parse should reject invalid private-name usage during the early-error walk. Hitting this at evaluation time means error-recovery mode skipped that walk, and the interpreter encountered a private name it cannot resolve. It is a defensive syntax error rather than a runtime data problem.
Solutions
- Remove or correct the `#name` reference; private fields are only valid inside class bodies declaring that field
- Check whether a Karate `#placeholder` leaked un-substituted into JS and quote or escape it appropriately
- Fix surrounding syntax errors so the early-error walk runs and reports the real location before evaluation
Example fix
// before
const v = obj.#secret; // invalid outside class
// after
class C { #secret = 1; get secret() { return this.#secret; } }
const v = new C().secret; Defensive patterns
Strategy: try-catch
Validate before calling
// lint JS before eval: flag /(^|[^\w$])#[A-Za-z_$]/ outside class bodies
const badPrivate = /(^|[^\w$.])#\s*[A-Za-z_$]/.test(jsSource) && !/class[\s{]/.test(jsSource); Try / catch
try { karate.eval(js); } catch (e) { if (String(e).includes('unexpected private name')) { /* surface a syntax-fix hint to the author */ } } Prevention
- Do not use #identifiers in embedded Karate JS — # is Karate placeholder syntax
- Use private fields only inside class bodies that declare them
- Lint embedded JS snippets before evaluation to catch private-name syntax early
When it happens
Trigger: Evaluating JS containing a `#privateName` reference outside valid class private-field context (e.g. `obj.#x` or a bare `#x`) when parsing runs in error-recovery mode that defers early errors to evaluation.
Common situations: Typing `#` prefixed identifiers in embedded JS (also colliding with Karate's own `#variable` placeholder syntax getting into JS); partial/invalid code evaluated incrementally by tooling; copy-paste of class private-field code into non-class scope.
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
- private name is not declared in an enclosing class
- ${hint: names offending unquoted object-literal keys…
- parser state: [ ]
- unexpected private name
- cannot delete private member
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/8c9c42b58687945f.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/Interpreter.java:3358
case ASSIGN_EXPR -> evalAssignExpr(node, context);
case BLOCK -> evalBlock(node, context);
case BREAK_STMT -> evalBreakStmt(node, context);
case CONTINUE_STMT -> evalContinueStmt(node, context);
case LABELLED_STMT -> evalLabelledStmt(node, context);
case DELETE_EXPR -> evalDeleteExpr(node, context);
case EXPR -> evalExpr(node, context);
case EXPR_LIST -> evalExprList(node, context);
case LIT_EXPR -> evalLitExpr(node, context);
case FN_EXPR -> evalFnExpr(node, context);
case FN_ARROW_EXPR -> evalFnArrowExpr(node, context);
case FN_CALL_EXPR -> chainStepResult(evalFnCall(node, context, false), node);
case FN_TAGGED_TEMPLATE_EXPR -> chainStepResult(evalFnTaggedTemplate(node, context), node);
case FOR_STMT -> evalForStmt(node, context);
case IF_STMT -> evalIfStmt(node, context);
case INSTANCEOF_EXPR -> evalInstanceOfExpr(node, context);
case IN_EXPR -> evalInExpr(node, context);
// only reachable in error-recovery mode, which skips the early-error walk
case PRIVATE_NAME_EXPR -> throw JsErrorException.syntaxError(
"unexpected private name " + node.getText());
case LOGIC_EXPR -> evalLogicExpr(node, context);
case LOGIC_AND_EXPR -> evalLogicAndExpr(node, context);
case LOGIC_NULLISH_EXPR -> evalLogicNullishExpr(node, context);
case LOGIC_BIT_EXPR -> evalLogicBitExpr(node, context);
case LOGIC_TERN_EXPR -> evalLogicTernExpr(node, context);
case MATH_ADD_EXPR -> evalMathAddExpr(node, context);
case MATH_EXP_EXPR -> Terms.exp(lhsOperand(node, context), rhsOperand(node, context), context);
case MATH_MUL_EXPR -> evalMathMulExpr(node, context);
case MATH_POST_EXPR -> evalMathPostExpr(node, context);
case MATH_PRE_EXPR -> evalMathPreExpr(node, context);
case NEW_EXPR -> evalNewExpr(node, context);
case PAREN_EXPR -> eval(node.get(1), context);
case CLASS_EXPR -> evalClassExpr(node, context);
case SUPER_EXPR -> evalSuperBase(context); // base for super.x / super[x] reads
case PROGRAM -> evalProgram(node, context);
case REF_EXPR -> evalRefExpr(node, context);View on GitHub (pinned to a22eb90246)