{"record":{"id":"f3c2b7cd41368307","repo":"apache/skywalking","slug":"unmatched-metrics-data-type-request-for-but-d","errorCode":null,"errorMessage":"Unmatched metrics data type, request for {}, but defined as {}","messagePattern":"Unmatched metrics data type, request for (.+?), but defined as (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterSystem.java","lineNumber":730,"sourceCode":"\n    /**\n     * Create an {@link AcceptableValue} instance for streaming calculation. AcceptableValue instance is stateful,\n     * shouldn't do {@link AcceptableValue#accept(MeterEntity, Object)} once it is pushed into {@link\n     * #doStreamingCalculation(AcceptableValue)}.\n     *\n     * @param metricsName A defined metrics name. Use {@link #create(String, String, ScopeType, Class)} to define a new\n     *                    one.\n     * @param dataType    class type of the input of {@link AcceptableValue}\n     * @return usable an {@link AcceptableValue} instance.\n     */\n    public <T> AcceptableValue<T> buildMetrics(String metricsName,\n                                               Class<T> dataType) {\n        MeterDefinition meterDefinition = meterPrototypes.get(metricsName);\n        if (meterDefinition == null) {\n            throw new IllegalArgumentException(\"Uncreated metrics \" + metricsName);\n        }\n        if (!meterDefinition.getDataType().equals(dataType)) {\n            throw new IllegalArgumentException(\n                \"Unmatched metrics data type, request for \" + dataType.getName()\n                    + \", but defined as \" + meterDefinition.getDataType());\n        }\n\n        return meterDefinition.getMeterPrototype().createNew();\n    }\n\n    /**\n     * Active the {@link MetricsStreamProcessor#in(Metrics)} for streaming calculation.\n     *\n     * @param acceptableValue should only be created through {@link #create(String, String, ScopeType, Class)}\n     */\n    public void doStreamingCalculation(AcceptableValue acceptableValue) {\n        final long timeBucket = acceptableValue.getTimeBucket();\n        if (timeBucket == 0L) {\n            // Avoid no timestamp data, which could be harmful for the storage.\n            acceptableValue.setTimeBucket(TimeBucket.getMinuteTimeBucket(System.currentTimeMillis()));\n        }","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterSystem.java#L712-L748","documentation":"Beyond existence, buildMetrics verifies that the dataType the caller requests equals the dataType the metric was created with (the generic T of the function's AcceptableValue). A mismatch throws 'Unmatched metrics data type, request for X, but defined as Y' — the prototype only produces values of the defined type, so accepting the request would corrupt the stream.","triggerScenarios":"A rule or consumer calls buildMetrics(name, Long.class) while the metric was created with Double.class (e.g. avgDouble function), or requests a scalar type for a histogram metric created with BucketedValues.class; a refactor changed the function in the MAL rule but the calling code still passes the old type literal.","commonSituations":"Switching a MAL rule from avg to avgDouble at runtime while analyzer code keeps Long.class; custom exporters reading meter metrics; version upgrades that changed a function's value type.","solutions":["Pass the same Class the metric was created with — for avgDouble/sumDouble metrics that is Double.class, for avg/sum it is Long.class, for histogram/percentile metrics BucketedValues.class / PercentileArgument","If the type genuinely changed, remove and recreate the metric with the new function/type before resuming production"],"exampleFix":"// before\nmeterSystem.create(\"latency_avg\", \"avgDouble\", ScopeType.SERVICE, Double.class);\nAcceptableValue<Long> v = meterSystem.buildMetrics(\"latency_avg\", Long.class);\n\n// after\nAcceptableValue<Double> v = meterSystem.buildMetrics(\"latency_avg\", Double.class);","handlingStrategy":"type-guard","validationCode":"// central registry of metric -> value type, filled at create() time\nMap<String, Class<?>> metricTypes = new ConcurrentHashMap<>();\nmetricTypes.put(name, Double.class); // after create(name, \"avgDouble\", ..., Double.class)\nClass<?> expected = metricTypes.get(name);\nif (!expected.equals(dataType)) throw new IllegalStateException(\"Wrong type for \" + name);","typeGuard":"boolean typeMatchesDefinition(String name, Class<?> dataType, Map<String, Class<?>> registry) {\n    return dataType.equals(registry.get(name));\n}","tryCatchPattern":"try {\n    AcceptableValue<Double> v = meterSystem.buildMetrics(name, Double.class);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Unmatched metrics data type\")) {\n        throw new IllegalStateException(\"Type drift for \" + name + \": \" + e.getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["Record the dataType next to each metric name when creating it and always look it up for buildMetrics","When changing a MAL function's value type, update every consumer in the same change","Prefer typed helper methods (buildLongMetric/buildDoubleMetric) that encode the type once"],"tags":["meter-system","type-mismatch","mal","lifecycle"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}