apache/skywalking · error · IllegalExpressionException

Single to Single, left result is empty or has more than one

Error message

Single to Single, left result is empty or has more than one value.

What it means

Thrown by LROp.single2SingleNoLabeled when a binary arithmetic operation (+, -, *, /, ...) is applied to two SINGLE_VALUE operands but the LEFT operand's results list is empty, or its first MQEValues holds a number of values other than exactly 1. The MQE runtime models a scalar as exactly one MQEValues with exactly one MQEValue; anything else is not a valid scalar and the operation refuses to guess which value to use.

Source

Thrown at oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java:97

                                                          ExpressionResult singleRight,
                                                          int opType, LROp calculate) throws IllegalExpressionException {
        if (!singleLeft.isLabeledResult() && !singleRight.isLabeledResult()) { // no labeled with no labeled
            return single2SingleNoLabeled(singleLeft, singleRight, opType, calculate);
        } else if (singleLeft.isLabeledResult() && !singleRight.isLabeledResult()) { // labeled with no labeled
            return many2OneBinaryOp(singleLeft, singleRight, opType, calculate);
        } else if (!singleLeft.isLabeledResult() && singleRight.isLabeledResult()) { // no labeled with labeled
            return one2ManyBinaryOp(singleLeft, singleRight, opType, calculate);
        } else { // labeled with labeled
            return single2SingleLabeled(singleLeft, singleRight, opType, calculate);
        }
    }

    private static ExpressionResult single2SingleNoLabeled(ExpressionResult singleLeft,
                                                          ExpressionResult singleRight,
                                                          int opType, LROp calculate) throws IllegalExpressionException {
        if (singleLeft.getResults().isEmpty() ||
            singleLeft.getResults().get(0).getValues().size() != 1) {
            throw new IllegalExpressionException("Single to Single, left result is empty or has more than one value.");
        }

        if (singleRight.getResults().isEmpty() ||
            singleRight.getResults().get(0).getValues().size() != 1) {
            throw new IllegalExpressionException("Single to Single, right result is empty or has more than one value.");
        }

        ExpressionResult result = new ExpressionResult();
        MQEValue mqeValue = new MQEValue();
        MQEValues mqeValues = new MQEValues();
        mqeValues.getValues().add(mqeValue);
        result.getResults().add(mqeValues);
        result.setType(ExpressionResultType.SINGLE_VALUE);

        MQEValue left = singleLeft.getResults().get(0).getValues().get(0);
        MQEValue right = singleRight.getResults().get(0).getValues().get(0);
        //return null if one of them is empty
        if (left.isEmptyValue() || right.isEmptyValue()) {

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Verify the left operand of the binary expression actually returns exactly one value, e.g. run the left side alone as an MQE query and inspect results[0].values length
  2. Wrap the left operand in an aggregation that guarantees a single value, such as sum(metricA) or avg(metricA), instead of using the raw metric
  3. If the left operand is empty because no data exists yet, guard the expression or accept the IllegalExpressionException as the documented empty-input signal
  4. Check for label manipulation (relabels/onLabel) on the left metric that changed its result shape from scalar to labeled, and adjust which side carries the labels

Example fix

// before
query: service_sla / service_cpm
// after (force single values on both sides)
query: sum(service_sla) / sum(service_cpm)
Defensive patterns

Strategy: validation

Validate before calling

ExpressionResult left = mqeService.eval(leftExpr);
boolean ok = left.getResults().size() == 1
    && left.getResults().get(0).getValues().size() == 1
    && left.getType() == ExpressionResultType.SINGLE_VALUE
    && !left.getResults().get(0).getValues().get(0).isEmptyValue();

Try / catch

catch (IllegalExpressionException e) { /* surface e.getMessage() to the query client; message names the offending side */ }

Prevention

When it happens

Trigger: An MQE expression like 'metricA / metricB' (or scalar op scalar) where the left sub-expression was typed SINGLE_VALUE (e.g. produced by aggregation like sum(), or a literal) but its results collection is empty or contains multiple values. This path is only reached when NEITHER side is a labeled result (single2SingleBinaryOp, LROp.java:81-82).

Common situations: A metric query returns no data for the left operand (empty results) while its type is still SINGLE_VALUE; mixing a scalar metric with a relabeled/labeled metric so the type detection misclassifies it; upgrading OAP versions where a metric's expression result shape changed; querying a metric name that exists in the schema but has never received data.

Related errors


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