{"record":{"id":"eb8bace52b7483c4","repo":"apache/skywalking","slug":"latest-can-only-be-used-in-time-series-result","errorCode":null,"errorMessage":"LATEST can only be used in time series result.","messagePattern":"LATEST can only be used in time series result\\.","errorType":"exception","errorClass":"IllegalExpressionException","httpStatus":null,"severity":"error","filePath":"oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/AggregationOp.java","lineNumber":52,"sourceCode":"import org.apache.skywalking.oap.server.core.query.mqe.MQEValues;\n\npublic class AggregationOp {\n    public static ExpressionResult doAggregationOp(ExpressionResult result,\n                                                   int opType) throws IllegalExpressionException {\n        switch (opType) {\n            case MQEParser.AVG:\n                return aggregateResult(result, mqeValues -> mqeValues.getValues()\n                                                                     .stream()\n                                                                     .filter(mqeValue -> !mqeValue.isEmptyValue())\n                                                                     .flatMapToDouble(mqeValue -> DoubleStream.of(\n                                                                         mqeValue.getDoubleValue()))\n                                                                     .average());\n            case MQEParser.COUNT:\n                return aggregateResult(result, mqeValues -> OptionalDouble.of(\n                    mqeValues.getValues().stream().filter(mqeValue -> !mqeValue.isEmptyValue()).count()));\n            case MQEParser.LATEST:\n                if (result.getType() != ExpressionResultType.TIME_SERIES_VALUES) {\n                    throw new IllegalExpressionException(\"LATEST can only be used in time series result.\");\n                }\n                return selectResult(result, mqeValues -> Streams.findLast(mqeValues.getValues()\n                                                                                   .stream()\n                                                                                   .filter(mqeValue -> !mqeValue.isEmptyValue())));\n            case MQEParser.MAX:\n                return selectResult(result, mqeValues -> mqeValues.getValues()\n                                                                  .stream()\n                                                                  .filter(mqeValue -> !mqeValue.isEmptyValue())\n                                                                  .max(Comparator.comparingDouble(\n                                                                      MQEValue::getDoubleValue)));\n            case MQEParser.MIN:\n                return selectResult(result, mqeValues -> mqeValues.getValues()\n                                                                  .stream()\n                                                                  .filter(mqeValue -> !mqeValue.isEmptyValue())\n                                                                  .min(Comparator.comparingDouble(\n                                                                      MQEValue::getDoubleValue)));\n            case MQEParser.SUM:\n                return aggregateResult(result, mqeValues -> OptionalDouble.of(mqeValues.getValues()","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/mqe-rt/src/main/java/org/apache/skywalking/mqe/rt/operation/AggregationOp.java#L34-L70","documentation":"IllegalExpressionException from AggregationOp: the LATEST aggregation only has meaning over a time-ordered series, so it requires the input ExpressionResult to be of type TIME_SERIES_VALUES. Applying LATEST (e.g. via latest(...)) to a SINGLE_VALUE, SORTED_LIST or RECORD_LIST result is rejected before evaluation.","triggerScenarios":"An MQE expression where latest() is applied to a non-timeseries operand, e.g. 'latest(aggregate_labels(metric, SUM))' if the inner result is no longer time-series, or latest() on top of a relabel/sort step that changed the result type to a list of records.","commonSituations":"Chaining MQE functions that change result type (topN/sort produce SORTED_LIST; aggregateLabels on a single point can collapse the series); users expecting latest() to mean 'last element' of any list.","solutions":["Reorder the expression so latest() directly wraps the time-series metric before type-changing ops: latest(metric.sum(dt5m))","Replace latest() with an appropriate function for list inputs (e.g. topN or takeLast-style op per the MQE docs for your result shape)","Inspect the inner expression's result type in the UI error context and adjust until the operand is TIME_SERIES_VALUES","If you need the most recent value of a labeled series, aggregate labels after latest(), not before"],"exampleFix":"# before\nlatest(aggregate_labels(service_resp_time.irate(dt5m), AVG))\n# after\naggregate_labels(latest(service_resp_time.irate(dt5m)), AVG)","handlingStrategy":"validation","validationCode":"// latest() requires a TIME_SERIES_VALUES operand — ensure no type-changing op (topn/sort/relabel) sits inside it\nboolean operandIsTimeSeries(ExpressionResult inner) { return inner.getType() == ExpressionResultType.TIME_SERIES_VALUES; }","typeGuard":"boolean canApplyLatest(org.apache.skywalking.oap.server.core.query.mqe.ExpressionResult r) {\n    return r.getType() == org.apache.skywalking.oap.server.core.query.mqe.ExpressionResultType.TIME_SERIES_VALUES;\n}","tryCatchPattern":null,"preventionTips":["Apply latest() directly to the raw time-series metric","Keep type-changing ops (topn, sort) outside latest()","Verify intermediate result types in the UI before nesting"],"tags":["mqe","aggregation","latest","type-mismatch","query"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}