apache/skywalking · error · IllegalArgumentException

Operator '{opSymbol}' requires numeric operands; got non-num

Error message

Operator '{opSymbol}' requires numeric operands; got non-numeric expression. Cast operands with 'as Integer/Long/Float/Double' to enable arithmetic.

What it means

Thrown at LAL compile time when a binary arithmetic operator other than + is applied to an operand the type inference does not consider numeric. Only + has a string-concatenation fallback; -, *, /, % require both sides to be statically numeric. Since parsed values from json{}/yaml{} are untyped Objects, the codegen cannot prove numericness and rejects the expression, suggesting an explicit 'as' cast.

Source

Thrown at oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALValueCodegen.java:1561

        String accExpr = accBuf.toString();

        for (int i = 1; i < parts.size(); i++) {
            final LALScriptModel.BinaryOp op = ops.get(i - 1);
            final ExprType rhsType = inferType(parts.get(i), genCtx);
            final StringBuilder rhsBuf = new StringBuilder();
            appendOperandRaw(rhsBuf, parts.get(i), rhsType, genCtx);
            final String rhsExpr = rhsBuf.toString();

            if (accType.isNumeric() && rhsType.isNumeric()) {
                final ExprType promoted = promote(accType, rhsType);
                final String widenedAcc = widenPrimitiveExpr(accExpr, accType, promoted);
                final String widenedRhs = widenPrimitiveExpr(rhsExpr, rhsType, promoted);
                accExpr = "(" + widenedAcc + " " + op.symbol() + " " + widenedRhs + ")";
                accType = promoted;
                continue;
            }
            if (op != LALScriptModel.BinaryOp.PLUS) {
                throw new IllegalArgumentException(
                    "Operator '" + op.symbol() + "' requires numeric operands; "
                        + "got non-numeric expression. Cast operands with "
                        + "'as Integer/Long/Float/Double' to enable arithmetic.");
            }
            // String concat path. Java's `+` only accepts the chain when
            // at least one operand is statically a String; otherwise (e.g.
            // `int + Object` or `Object + Object`) the source won't even
            // compile. Prepend a leading `""` whenever neither side is
            // statically String at the transition point. The numeric
            // arithmetic prefix is already in parens, so `("" + (1 + 2))`
            // still computes the sum first ("3"), preserving the
            // semantics of `1 + 2 + parsed.x` (= "3<obj>").
            if (accType != ExprType.STRING && rhsType != ExprType.STRING) {
                accExpr = "\"\" + " + accExpr;
            }
            accExpr = accExpr + " + " + rhsExpr;
            accType = ExprType.STRING;
        }

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Cast every operand with an explicit 'as' cast, e.g. (parsed.latency as Long) - (parsed.base as Long)
  2. Cast at least the accumulator-side of the chain so inference promotes correctly: parsed.latency as Long - 100
  3. For string concatenation use + (it falls back to concat), not other operators

Example fix

# before
timestamp parsed.ts - parsed.offset

# after
timestamp (parsed.ts as Long) - (parsed.offset as Long)
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: parsed.latency - 100 where parsed.* is map-typed (Object); parsed.count * parsed.factor without casts; arithmetic on safe-navigated chains (parsed?.x / 2) whose static type is Object.

Common situations: Computing latency/duration deltas from parsed JSON fields; porting Groovy v1 rules that did dynamic numeric coercion at runtime; metric expressions in the extractor that mix strings and numbers.

Related errors


AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14). Data as JSON: /api/errors/938ad7f5685e7dd0. Report an issue: GitHub.