{"record":{"id":"07ac715010316eff","repo":"apache/beam","slug":"scale-should-be-less-than-d-d","errorCode":null,"errorMessage":"Scale should be less than %d: %d","messagePattern":"Scale should be less than (.+?): (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/util/HistogramData.java","lineNumber":539,"sourceCode":"    /* 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\n     * (uint32 max). This value is log_base(2^32) which simplifies as follows:\n     *\n     * <pre>\n     * log_base(2^32)\n     * = log_2(2^32)/log_2(base)\n     * = 32/(2**-scale)\n     * = 32*(2**scale)\n     * </pre>\n     */","sourceCodeStart":521,"sourceCodeEnd":557,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/util/HistogramData.java#L521-L557","documentation":"ExponentialBuckets.of(scale, numBuckets) also enforces an upper bound: scale greater than MAXIMUM_SCALE throws this IllegalArgumentException because such an exponent would overflow bucket-range representation. The message names the maximum allowed scale.","triggerScenarios":"Calling ExponentialBuckets.of(scale, numBuckets) with an excessively large scale (scale > MAXIMUM_SCALE), often from unbounded user input or a derived computation without clamping.","commonSituations":"Accepting histogram resolution from user configuration without validating it; deriving scale from data magnitudes that produce huge exponents; copying scale constants from APIs with wider allowed ranges.","solutions":["Clamp scale to <= MAXIMUM_SCALE before calling of()","Validate user-supplied histogram configuration at pipeline-construction time","Check that the scale isn't accidentally expressed in different units (e.g. bits vs digits)"],"exampleFix":"// before\nint scale = userConfig.getScale(); // could be 1000\nExponentialBuckets.of(scale, 32);\n// after\nint scale = Math.min(HistogramData.ExponentialBuckets.MAXIMUM_SCALE, userConfig.getScale());\nExponentialBuckets.of(scale, 32);","handlingStrategy":"validation","validationCode":"if (scale > HistogramData.ExponentialBuckets.MAXIMUM_SCALE) {\n  throw new IllegalArgumentException(\"scale exceeds maximum: \" + scale);\n}","typeGuard":null,"tryCatchPattern":"try {\n  buckets = ExponentialBuckets.of(scale, numBuckets);\n} catch (IllegalArgumentException e) {\n  LOG.warn(\"Clamping scale {} to max and retrying\", scale);\n  buckets = ExponentialBuckets.of(HistogramData.ExponentialBuckets.MAXIMUM_SCALE, numBuckets);\n}","preventionTips":["Clamp user-supplied scale to MAXIMUM_SCALE","Check units of scale values coming from external configs"],"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"}