apache/skywalking · error · IllegalExpressionException

TopN type is not consistent, one is {}, another is {}

Error message

TopN type is not consistent, one is {}, another is {}

What it means

TopNOfOp.doMergeTopNResult merges the results of multiple topN(...) sub-expressions into one TopN list. All merged ExpressionResults must share the same ExpressionResultType; mixing types (e.g. one SORTED_LIST and one RECORD_LIST) throws this parameterized exception naming both conflicting types.

Source

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

import org.apache.skywalking.oap.server.core.query.mqe.ExpressionResult;
import org.apache.skywalking.oap.server.core.query.mqe.ExpressionResultType;
import org.apache.skywalking.oap.server.core.query.mqe.MQEValue;
import org.apache.skywalking.oap.server.core.query.mqe.MQEValues;
import org.apache.skywalking.oap.server.library.util.StringUtil;

public class TopNOfOp {
    public static ExpressionResult doMergeTopNResult(List<ExpressionResult> topNResults,
                                                     int limit,
                                                     int order) throws IllegalExpressionException {
        ExpressionResultType type = null;
        List<MQEValue> allValues = new ArrayList<>();
        for (ExpressionResult topNResult : topNResults) {
            if (StringUtil.isNotEmpty(topNResult.getError())) {
                return topNResult;
            }
            // check the type of topNResults
            if (type != null && type != topNResult.getType()) {
                throw new IllegalExpressionException("TopN type is not consistent, one is " + type + ", another is " +
                                                          topNResult.getType());
            }
            type = topNResult.getType();
            // topN result should have values without label
            allValues.addAll(topNResult.getResults().get(0).getValues());
        }
        if (limit > allValues.size()) {
            limit = allValues.size();
        }
        List<MQEValue> mergedValues = allValues.stream()
                                               // Filter out empty values
                                               .filter(mqeValue -> !mqeValue.isEmptyValue())
                                               .sorted(MQEParser.ASC == order ? Comparator.comparingDouble(
                                                   MQEValue::getDoubleValue) :
                                                           Comparator.comparingDouble(MQEValue::getDoubleValue)
                                                                     .reversed())
                                               .limit(limit).collect(Collectors.toList());

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Run each topN(...) operand alone and check its type in the response; make them identical
  2. Only merge TopN queries over metrics of the same kind (same OAL metric type and labels shape)
  3. If types genuinely differ, issue separate queries and merge client-side
  4. After OAL/metric redefinition changes, re-verify the metric types before merging

Example fix

// before
query: topN(service_sla) + topN(endpoint_cpm)  // one SORTED_LIST, one RECORD_LIST
// after
query: topN(service_sla) + topN(service_cpm)   // both same metric kind
Defensive patterns

Strategy: type-guard

Validate before calling

ExpressionResultType first = results.get(0).getType();
boolean consistent = results.stream().allMatch(r -> r.getType() == first);

Type guard

boolean isMergeableTopN(List<ExpressionResult> rs) {
    ExpressionResultType t = rs.get(0).getType();
    return rs.stream().allMatch(r -> r.getType() == t && r.getError() == null);
}

Try / catch

catch (IllegalExpressionException e) { /* message names both mismatched types — align operand metric kinds */ }

Prevention

When it happens

Trigger: An MQE expression like 'topN(a) + topN(b)' (topN merge) where the sub-queries resolve to different result types — for example one operand is a TopN metric (SORTED_LIST/RECORD_LIST) and the other returns SINGLE_VALUE or TIME_SERIES_VALUES, or two record types with different shapes.

Common situations: Combining a service TopN metric with an endpoint or instance metric of a different type; one of the merged metrics redefined in OAL from record to metric (or vice versa) after an upgrade; mixing topN of a normal metric with topN of a labeled/relabeled expression whose type differs

Related errors


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