karatelabs/karate · error · ParserException

private name is not declared in an enclosing class

Error message

private name ${name} is not declared in an enclosing class

What it means

A private name may only be used inside the class (or nested class) whose body declares it. Karate tracks PrivateScope objects per class body during parsing; when a private name is referenced (or a member key resolves) but the enclosing scope chain has no class declaring that name, requirePrivateDeclared throws this early error.

Solutions

  1. Declare the private name in the enclosing class body (e.g. `class C { #x; ... }`)
  2. Fix the spelling of the private name to match its declaration
  3. Move the usage inside the class that declares the private name

Example fix

// before
class C { m() { return #x in this; } }
// after
class C { #x; m() { return #x in this; } }
Defensive patterns

Strategy: validation

Validate before calling

// Verify every referenced #name is declared in the class body:
const used = new Set(js.match(/#\w+/g) || []);
const declared = new Set((js.match(/\s#\w+\s*[=;(]/g) || []).map(s => s.trim().split(/\s|\b/)[0]));

Try / catch

try { eval(js); } catch (e) { if (String(e).includes('is not declared in an enclosing class')) { /* declare the private name in the class */ } throw e; }

Prevention

When it happens

Trigger: Referencing `#x` (in an `in` check, member access, or declaration-dependent position) when privates is null (not inside any class body) or the enclosing PrivateScope does not declare the name — e.g. using a private name of an outer class from unrelated code, or a typo in the private name.

Common situations: Typos in private names (`#lenght` vs `#length`), using private members outside the class body, copy-pasting methods between classes where the target class lacks the private declaration.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/da33b7178e1c5f99. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/parser/JsParser.java:315

                    }
                    if (target.type == NodeType.PAREN_EXPR) {
                        target = target.size() > 1 ? target.get(1) : null;
                    } else if (target.type == NodeType.EXPR || target.type == NodeType.EXPR_LIST) {
                        target = target.size() == 1 ? target.getFirst() : null;
                    } else {
                        break;
                    }
                }
            }
            default -> {
            }
        }
        return privates;
    }

    private static void requirePrivateDeclared(String name, PrivateScope privates) {
        if (privates == null || !privates.declares(name)) {
            throw new ParserException("private name " + name + " is not declared in an enclosing class");
        }
    }

    /** Collects the {@code #name} keys declared directly by a class body. Each
     *  CLASS_METHOD holds its key as a direct token child, so at most one
     *  PRIVATE_NAME can appear per member (an initializer lives in a nested EXPR). */
    private static PrivateScope classPrivateScope(Node classNode, PrivateScope parent) {
        Set<String> names = null;
        Map<String, Integer> kinds = null;
        for (int i = 0, n = classNode.size(); i < n; i++) {
            Node member = classNode.get(i);
            if (member.type != NodeType.CLASS_METHOD) {
                continue;
            }
            Node key = null;
            int kind = 4; // 1 = get, 2 = set, 4 = anything else; 8 = static
            for (int j = 0, m = member.size(); j < m; j++) {
                Node c = member.get(j);

View on GitHub (pinned to a22eb90246)