{"record":{"id":"767d0bb66baa086c","repo":"apache/skywalking","slug":"topn-type-is-not-consistent-one-is-another-is","errorCode":null,"errorMessage":"TopN type is not consistent, one is {}, another is {}","messagePattern":"TopN type is not consistent, one is (.+?), another is (.+?)","errorType":"exception","errorClass":"IllegalExpressionException","httpStatus":null,"severity":"error","filePath":"oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/TopNOfOp.java","lineNumber":45,"sourceCode":"import org.apache.skywalking.oap.server.core.query.mqe.ExpressionResult;\nimport org.apache.skywalking.oap.server.core.query.mqe.ExpressionResultType;\nimport org.apache.skywalking.oap.server.core.query.mqe.MQEValue;\nimport org.apache.skywalking.oap.server.core.query.mqe.MQEValues;\nimport org.apache.skywalking.oap.server.library.util.StringUtil;\n\npublic class TopNOfOp {\n    public static ExpressionResult doMergeTopNResult(List<ExpressionResult> topNResults,\n                                                     int limit,\n                                                     int order) throws IllegalExpressionException {\n        ExpressionResultType type = null;\n        List<MQEValue> allValues = new ArrayList<>();\n        for (ExpressionResult topNResult : topNResults) {\n            if (StringUtil.isNotEmpty(topNResult.getError())) {\n                return topNResult;\n            }\n            // check the type of topNResults\n            if (type != null && type != topNResult.getType()) {\n                throw new IllegalExpressionException(\"TopN type is not consistent, one is \" + type + \", another is \" +\n                                                          topNResult.getType());\n            }\n            type = topNResult.getType();\n            // topN result should have values without label\n            allValues.addAll(topNResult.getResults().get(0).getValues());\n        }\n        if (limit > allValues.size()) {\n            limit = allValues.size();\n        }\n        List<MQEValue> mergedValues = allValues.stream()\n                                               // Filter out empty values\n                                               .filter(mqeValue -> !mqeValue.isEmptyValue())\n                                               .sorted(MQEParser.ASC == order ? Comparator.comparingDouble(\n                                                   MQEValue::getDoubleValue) :\n                                                           Comparator.comparingDouble(MQEValue::getDoubleValue)\n                                                                     .reversed())\n                                               .limit(limit).collect(Collectors.toList());\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/TopNOfOp.java#L27-L63","documentation":"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.","triggerScenarios":"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.","commonSituations":"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","solutions":["Run each topN(...) operand alone and check its type in the response; make them identical","Only merge TopN queries over metrics of the same kind (same OAL metric type and labels shape)","If types genuinely differ, issue separate queries and merge client-side","After OAL/metric redefinition changes, re-verify the metric types before merging"],"exampleFix":"// before\nquery: topN(service_sla) + topN(endpoint_cpm)  // one SORTED_LIST, one RECORD_LIST\n// after\nquery: topN(service_sla) + topN(service_cpm)   // both same metric kind","handlingStrategy":"type-guard","validationCode":"ExpressionResultType first = results.get(0).getType();\nboolean consistent = results.stream().allMatch(r -> r.getType() == first);","typeGuard":"boolean isMergeableTopN(List<ExpressionResult> rs) {\n    ExpressionResultType t = rs.get(0).getType();\n    return rs.stream().allMatch(r -> r.getType() == t && r.getError() == null);\n}","tryCatchPattern":"catch (IllegalExpressionException e) { /* message names both mismatched types — align operand metric kinds */ }","preventionTips":["Only merge topN over metrics of the same OAL kind","Run each topN operand alone and compare result types before merging","Re-verify metric types after OAL redefinitions"],"tags":["mqe","query-engine","topn","type-mismatch"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}