karatelabs/karate · error · JsErrorException (typeError)

cannot apply logical-assignment to

Error message

cannot apply logical-assignment to: ${node}

What it means

A TypeError thrown when a logical assignment operator (`||=`, `&&=`, `??=`) is applied to a parse-tree node type that is neither a variable reference nor a member access. It is the default arm of the switch in PropertyAccess.logicalCompound, so it indicates an LHS shape the evaluator cannot treat as an assignment reference.

Solutions

  1. Rewrite the statement so the LHS is a variable or property access
  2. Compute the expression into a variable, then apply the logical assignment to that variable
  3. If the LHS appears valid, check for a parser regression and upgrade the engine

Example fix

// before
foo().bar ??= 1;
// after
let f = foo();
f.bar ??= 1;
Defensive patterns

Strategy: validation

Validate before calling

// Reject logical-assignment statements whose LHS is not an identifier/member
if (/[^=!<>]=(&&|\|\||\?\?)?\s*(?![\w$.[])/.test(code)) { /* lint target */ }
// preferred: parse and check node type before eval
// valid = ['Identifier','MemberExpression'].includes(lhs.type)

Type guard

function isLogicalAssignTarget(lhsNode) {
  return lhsNode && ['Identifier','MemberExpression'].includes(lhsNode.type);
}

Prevention

When it happens

Trigger: Executing a script whose logical-assignment LHS parses as something other than REF_EXPR / REF_DOT_EXPR / REF_BRACKET_EXPR — e.g. `(a + b) ||= 1`, assignment to a call result, or a malformed/generated AST.

Common situations: Hand-edited JS with an expression on the left of `||=`; code generators emitting invalid assignment targets; engine/parser version mismatch.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java:453

                    PrivateAccess.set(site.target, site.privateName, newValue, context);
                    yield newValue;
                }
                if (site.receiver != null) {
                    // super reference — the fused by-index/by-name workers
                    // below have no receiver seam; run the generic sequence.
                    Object oldValue = siteRead(site, context);
                    if (context.isStopped()) yield null;
                    if (!shouldLogicalAssign(operator, oldValue)) yield oldValue;
                    Object newValue = Interpreter.eval(rhsNode, context);
                    if (context.isStopped()) yield null;
                    siteWrite(site, newValue, context, trackingNode);
                    yield newValue;
                }
                yield site.isIndex
                        ? logicalCompoundByIndex(site.target, site.key, operator, rhsNode, context, trackingNode)
                        : logicalCompoundByName(site.target, (String) site.key, operator, rhsNode, context, trackingNode);
            }
            default -> throw JsErrorException.typeError("cannot apply logical-assignment to: " + node);
        };
    }

    // Name-keyed REF_EXPR tails, outlined from their switch cases to keep the
    // slot fast paths small enough to inline reliably.

    private static Object compoundRefByName(Node node, CoreContext context, TokenType operator, Node rhsNode, Node trackingNode) {
        String name = node.getText();
        Object oldValue = context.get(name);
        if (context.isStopped()) return Terms.UNDEFINED;
        Object operand = Interpreter.eval(rhsNode, context);
        if (context.isStopped()) return Terms.UNDEFINED;
        Object newValue = applyOperator(oldValue, operator, operand, context);
        context.update(name, newValue, trackingNode);
        return newValue;
    }

    private static Object logicalCompoundRefByName(Node node, CoreContext context, TokenType operator, Node rhsNode, Node trackingNode) {

View on GitHub (pinned to a22eb90246)