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

  1. Remove or correct the `#name` reference; private fields are only valid inside class bodies declaring that field
  2. Check whether a Karate `#placeholder` leaked un-substituted into JS and quote or escape it appropriately
  3. 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

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


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)