apache/skywalking · error · IllegalExpressionException
Unsupported operation.
Error message
Unsupported operation.
What it means
The core IllegalExpressionException from LROp.doLROp's type dispatch: the left/right ExpressionResultType combination matches none of the supported branches — SINGLE_VALUE×SINGLE_VALUE (scalar path, handled earlier), many(TIME_SERIES/SORTED_LIST/RECORD_LIST)×SINGLE, SINGLE×many, or TIME_SERIES×TIME_SERIES. This is the root cause message that BinaryOp, CompareOp and BoolOp re-wrap in their 'Unsupported X operation' errors.
Source
Thrown at oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/LROp.java:57
ExpressionResult right,
int opType, LROp calculate) throws IllegalExpressionException {
if (left.getType() == ExpressionResultType.SINGLE_VALUE && right.getType() == ExpressionResultType.SINGLE_VALUE) {
return single2SingleBinaryOp(left, right, opType, calculate);
} else if ((left.getType() == ExpressionResultType.TIME_SERIES_VALUES ||
left.getType() == ExpressionResultType.SORTED_LIST ||
left.getType() == ExpressionResultType.RECORD_LIST)
&& right.getType() == ExpressionResultType.SINGLE_VALUE) {
return many2OneBinaryOp(left, right, opType, calculate);
} else if (left.getType() == ExpressionResultType.SINGLE_VALUE &&
(right.getType() == ExpressionResultType.TIME_SERIES_VALUES ||
right.getType() == ExpressionResultType.SORTED_LIST ||
right.getType() == ExpressionResultType.RECORD_LIST)) {
return one2ManyBinaryOp(left, right, opType, calculate);
} else if (left.getType() == ExpressionResultType.TIME_SERIES_VALUES && right.getType() == ExpressionResultType.TIME_SERIES_VALUES) {
return seriesBinaryOp(left, right, opType, calculate);
}
throw new IllegalExpressionException("Unsupported operation.");
}
//series with series
private static ExpressionResult seriesBinaryOp(ExpressionResult seriesLeft,
ExpressionResult seriesRight,
int opType, LROp calculate) throws IllegalExpressionException {
ExpressionResult result = new ExpressionResult();
if (!seriesLeft.isLabeledResult() && !seriesRight.isLabeledResult()) { // no labeled with no labeled
result = seriesNoLabeled(seriesLeft, seriesRight, opType, calculate);
} else if (seriesLeft.isLabeledResult() && !seriesRight.isLabeledResult()) { // labeled with no labeled
result = seriesLabeledWithNoLabeled(seriesLeft, seriesRight, opType, calculate);
} else if (!seriesLeft.isLabeledResult() && seriesRight.isLabeledResult()) { // no labeled with labeled
result = seriesNoLabeledWithLabeled(seriesLeft, seriesRight, opType, calculate);
} else { // labeled with labeled
result = seriesLabeledWithLabeled(seriesLeft, seriesRight, opType, calculate);
}
return result;View on GitHub (pinned to 102af09b4a)
Solutions
- Identify both operand types (UI shows the result type of each sub-expression, or consult the MQE docs) and reshape so the pair is series×series, or one side a single value
- Apply aggregations to reduce lists to series before combining: aggregate_labels(x, SUM), or restructure so topn/records sit outside the arithmetic
- Compare/boolean operators additionally require boolean leaves — see the BoolOp-specific errors
- Simplify the expression into stages and verify each stage renders alone in the UI before combining
Example fix
# before topn(service_cpm.sum(dt5m), 10, DES) + topn(service_sla.sum(dt5m), 10, DES) # after (service_cpm.sum(dt5m) + service_sla.sum(dt5m)) # arithmetic on series; apply topn afterwards if needed
Defensive patterns
Strategy: type-guard
Validate before calling
boolean isLROpSupported(ExpressionResultType l, ExpressionResultType r) {
boolean manyL = l == TIME_SERIES_VALUES || l == SORTED_LIST || l == RECORD_LIST;
boolean manyR = r == TIME_SERIES_VALUES || r == SORTED_LIST || r == RECORD_LIST;
return (l == SINGLE_VALUE && r == SINGLE_VALUE)
|| (manyL && r == SINGLE_VALUE) || (l == SINGLE_VALUE && manyR)
|| (l == TIME_SERIES_VALUES && r == TIME_SERIES_VALUES);
} Type guard
boolean isBinaryOperandType(org.apache.skywalking.oap.server.core.query.mqe.ExpressionResultType t) {
return t == org.apache.skywalking.oap.server.core.query.mqe.ExpressionResultType.SINGLE_VALUE
|| t == org.apache.skywalking.oap.server.core.query.mqe.ExpressionResultType.TIME_SERIES_VALUES;
} Try / catch
catch (IllegalExpressionException e) { /* reshape: aggregate lists to series, or move topn/records outside the binary op */ } Prevention
- Build MQE expressions incrementally and check each intermediate's type
- Reduce SORTED_LIST/RECORD_LIST with aggregations before any binary operator
- Keep topn() and record queries at the outermost level only
When it happens
Trigger: Any MQE binary operation between two 'many' operands where at least one is not a time series: LIST×LIST, RECORD_LIST×SERIES, SORTED_LIST×RECORD_LIST, SINGLE×SINGLE arriving on the non-scalar path, etc. Example: 'topn(a,10) + topn(b,10)', 'queryLogs(...) > metric'.
Common situations: Combining two TopN results; mixing record queries (traces/logs) with metric arithmetic; combining labeled series under unsupported label-pairing branches; building complex dashboard expressions without checking each intermediate's result type.
Related errors
- Unsupported binary operation: {}
- Unsupported bool operation: {}
- Unsupported compare operation: {}
- Unsupported aggregateLabels function.
- LATEST can only be used in time series result.
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/65630887bc6e8cde.
Report an issue: GitHub.