karatelabs/karate · error · java.lang.RuntimeException
unexpected operator
Error message
unexpected operator: <operator>
What it means
PropertyAccess's compound-assignment evaluator applies numeric/bitwise compound operators (+=, <<=, >>>=, &=, |=, ^=, etc.) via a switch; the default branch throws "unexpected operator" when an operator token reaches this switch that it does not handle. Like shouldLogicalAssign, this is an internal invariant guard against a dispatch/grammar mismatch.
Solutions
- Note the operator in the message; rewrite the statement using an explicit binary form (x = x op y) to avoid the unsupported compound path.
- Upgrade Karate to a version whose evaluator supports the operator.
- If reproducible with a plain operator like +=, report it as a bug with a minimal reproducing script.
Example fix
// before (script) x >>>= 2; // unexpected operator: >>>= // after x = x >>> 2;
Defensive patterns
Strategy: validation
Validate before calling
// Only use compound operators known to be supported: += -= *= /= %= <<= >>= >>>= &= |= ^= **=
// and logical: ||= &&= ??=
if (opToken === '>>>=') rewriteAs('x = x >>> 2'); Type guard
function isSupportedCompoundOp(tok) {
return ['+=','-=','*=','/=','%=','<<=','>>=','>>>=','&=','|=','^=','||=','&&=','??='].includes(tok);
} Try / catch
try {
return karate.eval(script);
} catch (RuntimeException e) {
if (e.getMessage().contains("unexpected operator")) {
throw new IllegalStateException("script uses an unsupported compound operator", e);
}
throw e;
} Prevention
- Use only common compound-assignment operators in scripts.
- Upgrade Karate if a documented operator throws here — indicates version skew.
- Prefer explicit binary assignment (x = x op y) for exotic operators.
When it happens
Trigger: A compound-assignment expression whose operator is not among the implemented arithmetic/bitwise assignment tokens reaches the switch — a parser/evaluator inconsistency, e.g. a newly added operator token unsupported in evaluation.
Common situations: Rare in normal use; seen with a library version where the grammar accepts an operator the evaluator does not implement, or corrupted/generated scripts containing unusual assignment tokens.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- unexpected logical-assignment operator
- parser state: [ ]
- too much recursion
- invalid shorthand initializer: only allowed in…
- unexpected private name
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/582cad83ea744bdf.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java:1352
}
//=== Helper methods ===
private static Object applyOperator(Object oldValue, TokenType operator, Object operand, CoreContext context) {
return switch (operator) {
case PLUS_EQ -> Terms.add(oldValue, operand, context);
case MINUS_EQ -> Terms.min(oldValue, operand, context);
case STAR_EQ -> Terms.mul(oldValue, operand, context);
case SLASH_EQ -> Terms.div(oldValue, operand, context);
case PERCENT_EQ -> Terms.mod(oldValue, operand, context);
case STAR_STAR_EQ -> Terms.exp(oldValue, operand, context);
case GT_GT_EQ -> Terms.bitShiftRight(oldValue, operand, context);
case LT_LT_EQ -> Terms.bitShiftLeft(oldValue, operand, context);
case GT_GT_GT_EQ -> Terms.bitShiftRightUnsigned(oldValue, operand, context);
case AMP_EQ -> Terms.bitAnd(oldValue, operand, context);
case PIPE_EQ -> Terms.bitOr(oldValue, operand, context);
case CARET_EQ -> Terms.bitXor(oldValue, operand, context);
default -> throw new RuntimeException("unexpected operator: " + operator);
};
}
private static boolean isFound(Object result) {
return result != null && result != Terms.UNDEFINED;
}
/** Walks the prototype chain looking for an accessor slot at
* {@code name}. Returns the first {@link AccessorSlot} found, or
* {@code null} (no accessor in chain — write proceeds as a normal
* data put on the receiver). Stops at the first own slot at each
* level, even if it's a data slot — matches spec
* OrdinarySetWithOwnDescriptor semantics. */
private static AccessorSlot findAccessorInChain(ObjectLike obj, String name) {
ObjectLike current = obj;
while (current != null) {
PropertySlot s = ownSlot(current, name);
if (s instanceof AccessorSlot acc) return acc;View on GitHub (pinned to a22eb90246)