karatelabs/karate · error · ParserException

unary expression cannot be the base of '**'; wrap it in…

Error message

unary expression cannot be the base of '**'; wrap it in parentheses

What it means

The exponentiation operator `**` forbids a unary expression as its left operand (`-a ** 2` is an early error in JS to avoid ambiguity with `-(a ** 2)`). The Karate JS parser throws this when the base of a `**` expression is a unary/typeof/delete/await/minus-prefixed expression. Wrap the operand in parentheses to state intent.

Solutions

  1. Add parentheses: `(-x) ** 2` if you want the negated base, or `-(x ** 2)` if you want negation of the power.
  2. For `await`, use `(await p) ** 2`.
  3. For `typeof`/`delete` bases, restructure — they rarely make sense as exponent bases.

Example fix

// before
let area = -r ** 2;
// after
let area = (-r) ** 2; // or -(r ** 2)
Defensive patterns

Strategy: validation

Validate before calling

// flag unary bases under **
function hasUnaryBase(src) { return /(^|[\s(])[+-]\s*[\w$.]+\s*\*\*/.test(src); }

Try / catch

try { karate.eval(expr); } catch (e) { if (String(e).includes("cannot be the base of '**'")) { /* add parentheses */ } }

Prevention

When it happens

Trigger: Parsing expressions like `-x ** 2`, `+y ** 2`, `typeof a ** b`, `await p ** 2`, `delete o.k ** 2`, detected in earlyErrorNodeChecks for MATH_EXPR (power) nodes with a unary base.

Common situations: Porting math code like `-x ** 2` from Python (where it means `(-x) ** 2`) into JS; writing physics formulas with negated bases; code written by authors expecting C-like unary precedence.

Related errors


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

Appendix: source

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

                    TokenType op = node.size() > 1 && node.get(1).isToken() ? node.get(1).token.type : null;
                    boolean noCallCarveOut = op == PIPE_PIPE_EQ || op == AMP_AMP_EQ || op == QUES_QUES_EQ;
                    checkSimpleAssignmentTarget(lhs, "assignment target", noCallCarveOut);
                }
            }
            case MATH_EXP_EXPR -> {
                // §13.6: the base of `**` must be an UpdateExpression — an
                // unparenthesized unary (-x, !x, ~x, +x, void x, typeof x,
                // delete x.y, await x) is a SyntaxError; ++x / --x are legal.
                Node base = stripExprWrappers(node.size() > 0 ? node.getFirst() : null);
                if (base != null) {
                    boolean unaryBase = switch (base.type) {
                        case DELETE_EXPR, TYPEOF_EXPR, UNARY_EXPR, AWAIT_EXPR -> true;
                        case MATH_PRE_EXPR -> base.size() > 0 && base.getFirst().isToken()
                                && (base.getFirst().token.type == PLUS || base.getFirst().token.type == MINUS);
                        default -> false;
                    };
                    if (unaryBase) {
                        throw new ParserException("unary expression cannot be the base of '**'; wrap it in parentheses");
                    }
                }
            }
            case MATH_POST_EXPR -> {
                // children: [operand, ++/--]
                if (node.size() > 0) {
                    Node operand = node.getFirst();
                    if (sawOptionalChain && subtreeContainsOptionalChain(operand)) {
                        throw new ParserException("optional chain cannot be the operand of postfix ++/--");
                    }
                    checkSimpleAssignmentTarget(operand, "operand of postfix update", false);
                }
            }
            case MATH_PRE_EXPR -> {
                // children: [op, operand] — only ++/-- need a valid update target;
                // unary +/- have no assignment side and parse the same shape.
                if (node.size() > 1) {
                    Node op = node.getFirst();

View on GitHub (pinned to a22eb90246)