{"record":{"id":"9d8887a7a9bd3b90","repo":"apache/beam","slug":"scale-should-be-greater-than-d-d","errorCode":null,"errorMessage":"Scale should be greater than %d: %d","messagePattern":"Scale should be greater than (.+?): (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/util/HistogramData.java","lineNumber":530,"sourceCode":"     */\n    @Memoized\n    public double getInvLog2GrowthFactor() {\n      return Math.pow(2, getScale());\n    }\n\n    @Override\n    public abstract int getNumBuckets();\n\n    /* Memoized since this value is used everytime a datapoint is recorded. */\n    @Memoized\n    @Override\n    public double getRangeTo() {\n      return Math.pow(getBase(), getNumBuckets());\n    }\n\n    public static ExponentialBuckets of(int scale, int numBuckets) {\n      if (scale < MINIMUM_SCALE) {\n        throw new IllegalArgumentException(\n            String.format(\"Scale should be greater than %d: %d\", MINIMUM_SCALE, scale));\n      }\n\n      if (scale > MAXIMUM_SCALE) {\n        throw new IllegalArgumentException(\n            String.format(\"Scale should be less than %d: %d\", MAXIMUM_SCALE, scale));\n      }\n      if (numBuckets <= 0) {\n        throw new IllegalArgumentException(\n            String.format(\"numBuckets should be positive: %d\", numBuckets));\n      }\n\n      int clippedNumBuckets = ExponentialBuckets.computeNumberOfBuckets(scale, numBuckets);\n      return new AutoValue_HistogramData_ExponentialBuckets(scale, clippedNumBuckets);\n    }\n\n    /**\n     * numBuckets is clipped so that the largest bucket's lower bound is not greater than 2^32-1","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/util/HistogramData.java#L512-L548","documentation":"ExponentialBuckets.of(scale, numBuckets) validates the base-2 exponent scale against MINIMUM_SCALE before building the histogram bucket scheme. A scale below the minimum cannot represent a valid exponential histogram, so an IllegalArgumentException is thrown naming the required minimum.","triggerScenarios":"Calling HistogramData.ExponentialBuckets.of(scale, numBuckets) with a negative or too-small scale value (scale < MINIMUM_SCALE).","commonSituations":"Computing scale dynamically (e.g. from a width or resolution calculation) and the formula yields 0 or negative values; hardcoding scale values copied from other histogram APIs with different conventions.","solutions":["Pass a scale value >= MINIMUM_SCALE (check the constant in HistogramData for the exact bound)","Clamp computed scale values: Math.max(MINIMUM_SCALE, computedScale) before calling of()","Review where the scale originates; unit-test boundary values"],"exampleFix":"// before\nExponentialBuckets b = ExponentialBuckets.of(-2, 16);\n// after\nint scale = Math.max(HistogramData.ExponentialBuckets.MINIMUM_SCALE, computedScale);\nExponentialBuckets b = ExponentialBuckets.of(scale, 16);","handlingStrategy":"validation","validationCode":"if (scale < HistogramData.ExponentialBuckets.MINIMUM_SCALE) {\n  throw new IllegalArgumentException(\"scale below minimum: \" + scale);\n}","typeGuard":null,"tryCatchPattern":"try {\n  buckets = ExponentialBuckets.of(scale, numBuckets);\n} catch (IllegalArgumentException e) {\n  throw new IllegalArgumentException(\"Invalid histogram scale config: \" + scale, e);\n}","preventionTips":["Clamp computed scale values to [MINIMUM_SCALE, MAXIMUM_SCALE]","Unit-test boundary scale values"],"tags":["java","histogram","argument-validation"],"backgroundTag":"value-out-of-range","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}