{"record":{"id":"991af2c10eae7045","repo":"apache/cassandra","slug":"unable-to-compute-when-histogram-overflowed","errorCode":null,"errorMessage":"Unable to compute when histogram overflowed","messagePattern":"Unable to compute when histogram overflowed","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/utils/EstimatedHistogram.java","lineNumber":229,"sourceCode":"\n        for (int i = lastBucket - 1; i >= 0; i--)\n        {\n            if (buckets.get(i) > 0)\n                return bucketOffsets[i];\n        }\n        return 0;\n    }\n\n    /**\n     * @param percentile\n     * @return estimated value at given percentile\n     */\n    public long percentile(double percentile)\n    {\n        assert percentile >= 0 && percentile <= 1.0;\n        int lastBucket = buckets.length() - 1;\n        if (buckets.get(lastBucket) > 0)\n            throw new IllegalStateException(\"Unable to compute when histogram overflowed\");\n\n        long pcount = (long) Math.ceil(count() * percentile);\n        if (pcount == 0)\n            return 0;\n\n        long elements = 0;\n        for (int i = 0; i < lastBucket; i++)\n        {\n            elements += buckets.get(i);\n            if (elements >= pcount)\n                return bucketOffsets[i];\n        }\n        return 0;\n    }\n\n    /**\n     * @return the ceil of mean histogram value (average of bucket offsets, weighted by count)\n     * @throws IllegalStateException if any values were greater than the largest bucket threshold","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/utils/EstimatedHistogram.java#L211-L247","documentation":"EstimatedHistogram stores counts in offset buckets where the last bucket is the overflow bucket. percentile() cannot compute a percentile if any recorded value exceeded the largest bucket threshold, because the exact distribution is unknown, so it throws IllegalStateException.","triggerScenarios":"Calling percentile(...) (or data/mean paths through it) after at least one recorded value landed in the last (overflow) bucket, i.e. buckets.get(lastBucket) > 0.","commonSituations":"Latency histograms with extreme outliers exceeding the max bucket (default ~hours for latency histograms), long-running nodes with huge record latencies, or requesting percentiles from an inappropriately sized histogram.","solutions":["Construct the histogram with a larger bucket range (bigger offsets/max value) so expected values never overflow","Check isOverflowed()/the last bucket before calling percentile and skip or report overflow instead","For mean-like needs, use the overflow-aware alternatives where available rather than rawMean/percentile"],"exampleFix":"// before\nEstimatedHistogram h = new EstimatedHistogram(); // default range\nlong p = h.percentile(0.99); // throws if overflowed\n// after\nif (!h.isOverflowed()) {\n    long p = h.percentile(0.99);\n} else {\n    // handle overflow: report 'unknown'/create larger histogram\n}","handlingStrategy":"validation","validationCode":"long safePercentile(EstimatedHistogram h, double p) {\n    return h.isOverflowed() ? -1 : h.percentile(p); // -1 signals overflow\n}","typeGuard":null,"tryCatchPattern":"try {\n    long v = histogram.percentile(0.99);\n} catch (IllegalStateException e) {\n    // histogram overflowed: report unknown / use larger histogram\n}","preventionTips":["Check overflow state before computing percentiles","Size the histogram's bucket range to exceed realistic max values","Treat overflowed histograms as unreliable for percentile reporting"],"tags":["histogram","metrics","overflow","java"],"backgroundTag":"internal-invariant-violation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}