karatelabs/karate · error · ParserException

cannot delete private member

Error message

cannot delete private member ${name}

What it means

Per the class-fields spec, `delete` is not permitted on private field/method/accessor references. Karate's parser statically detects a PRIVATE_NAME key in a dot-reference under a DELETE_EXPR and rejects it at parse time, because deleting a private member would break class encapsulation invariants.

Solutions

  1. Remove the delete statement and instead assign a sentinel (e.g. `obj.#field = null`) if the field's semantics allow it
  2. Expose an explicit class method that performs the invalidation/reset the private member needs
  3. If the property must be deletable, make it a regular (non-private) property

Example fix

// before
delete obj.#cache;
// after
obj.#cache = null; // or call an explicit reset method
Defensive patterns

Strategy: validation

Validate before calling

// Scan for delete of private members:
const hasBadDelete = /delete\s+(?:\(\s*)?[\w$.]*\.#\w+/.test(src);

Try / catch

try { eval(js); } catch (e) { if (String(e).includes('cannot delete private member')) { /* replace with assignment/nulling */ } throw e; }

Prevention

When it happens

Trigger: Writing `delete obj.#field;` (or the same inside parentheses) anywhere the parser runs privateNodeChecks. The check descends through PAREN_EXPR/EXPR/EXPR_LIST wrappers to find a REF_DOT_EXPR whose key token is a PRIVATE_NAME.

Common situations: Attempting to 'reset' or remove a private field on an object; porting code that deleted plain properties and mechanically adding `#`; misunderstanding private fields as configurable properties.

Related errors


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

Appendix: source

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

                if (key != null && key.isToken() && key.token.type == PRIVATE_NAME) {
                    requirePrivateDeclared(key.getText(), privates);
                }
            }
            case PRIVATE_NAME_EXPR -> {
                Node parent = node.getParent();
                if (parent == null || parent.type != NodeType.IN_EXPR || parent.getFirst() != node) {
                    throw new ParserException("unexpected private name '" + node.getText()
                            + "': only valid as the left operand of `in`");
                }
                requirePrivateDeclared(node.getText(), privates);
            }
            case DELETE_EXPR -> {
                Node target = node.size() > 1 ? node.get(1) : null;
                while (target != null && !target.isToken()) {
                    if (target.type == NodeType.REF_DOT_EXPR) {
                        Node key = target.size() > 2 ? target.get(2) : null;
                        if (key != null && key.isToken() && key.token.type == PRIVATE_NAME) {
                            throw new ParserException("cannot delete private member " + key.getText());
                        }
                        break;
                    }
                    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;
    }

View on GitHub (pinned to a22eb90246)