{"record":{"id":"ef6d8d9a83a4eebf","repo":"apache/skywalking","slug":"buckets-and-values-can-t-be-null","errorCode":null,"errorMessage":"buckets and values can't be null.","messagePattern":"buckets and values can't be null\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/BucketedValues.java","lineNumber":59,"sourceCode":"     * The element in the buckets represent the minimal value of this bucket, the max is defined by the next element.\n     * Such as 0, 10, 50, 100 means buckets are [0, 10), [10, 50), [50, 100), [100, infinite+).\n     *\n     * The {@link Long#MIN_VALUE} could be the first bucket element to indicate there is no minimal value.\n     */\n    private long[] buckets;\n    /**\n     * {@link #buckets} and {@link #values} arrays should have the same length. The element in the values, represents\n     * the amount in the same index bucket.\n     */\n    private long[] values;\n\n    /**\n     * @param buckets Read {@link #buckets}\n     * @param values  Read {@link #values}\n     */\n    public BucketedValues(final long[] buckets, final long[] values) {\n        if (buckets == null || values == null || buckets.length == 0 || values.length == 0) {\n            throw new IllegalArgumentException(\"buckets and values can't be null.\");\n        }\n        if (buckets.length != values.length) {\n            throw new IllegalArgumentException(\"The length of buckets and values should be same.\");\n        }\n        this.buckets = buckets;\n        this.values = values;\n    }\n\n    /**\n     * @return true if the bucket is same.\n     */\n    public boolean isCompatible(DataTable dataset) {\n        final List<String> sortedKeys = dataset.sortedKeys(new HeatMap.KeyComparator(true));\n        long[] existedBuckets = new long[sortedKeys.size()];\n        for (int i = 0; i < sortedKeys.size(); i++) {\n            String key = sortedKeys.get(i);\n            if (key.equals(Bucket.INFINITE_NEGATIVE)) {\n                existedBuckets[i] = Long.MIN_VALUE;","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/BucketedValues.java#L41-L77","documentation":"BucketedValues is the value object histogram meter functions accept; its constructor requires a non-null, non-empty buckets array and a non-null, non-empty values array. Violating any of the four conditions (either array null or zero-length) throws this IllegalArgumentException before any aggregation happens, protecting downstream index arithmetic that assumes buckets.length > 0.","triggerScenarios":"A MAL rule or agent SDK builds BucketedValues from empty or null telemetry — e.g. a bucketed expression produced no points this cycle, or upstream code passes uninitialized arrays; a custom meter sender serializes an empty histogram.","commonSituations":"Meter/OTel receivers forwarding empty histogram batches; agent plugins computing buckets conditionally and passing null when the condition fails; test fixtures with empty arrays.","solutions":["Skip emitting the histogram metric for this cycle when buckets or values would be empty instead of constructing BucketedValues","Fix the producer so it always sends a well-formed bucket set (bucket boundaries plus one value per bucket)","Validate telemetry at the receiving boundary and reject/log malformed empty histograms before they reach accept()"],"exampleFix":"// before\nlong[] buckets = fetchBuckets(); // may be empty\nnew BucketedValues(buckets, values);\n\n// after\nlong[] buckets = fetchBuckets();\nif (buckets != null && buckets.length > 0 && values != null && values.length == buckets.length) {\n    new BucketedValues(buckets, values);\n} else {\n    log.debug(\"Skip empty histogram for {}\", metricName);\n}","handlingStrategy":"validation","validationCode":"if (buckets == null || values == null || buckets.length == 0 || values.length == 0) {\n    log.debug(\"Skipping empty histogram for {}\", metricName);\n} else {\n    BucketedValues bv = new BucketedValues(buckets, values);\n    histogram.accept(entity, bv);\n}","typeGuard":"boolean isWellFormedHistogram(long[] buckets, long[] values) {\n    return buckets != null && values != null\n        && buckets.length > 0 && values.length == buckets.length;\n}","tryCatchPattern":null,"preventionTips":["Guard every histogram emission site with a null/empty check instead of relying on OAP to reject it","Never send placeholder empty histograms for 'no data this cycle' — simply omit the point","Validate at the receiver boundary so one misbehaving agent cannot disrupt aggregation"],"tags":["meter-system","histogram","validation","mal"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}