{"record":{"id":"23437606292f3ac4","repo":"apache/druid","slug":"last-bitmapfullnessfactorizationstop-d-should-be","errorCode":null,"errorMessage":"Last bitmapFullnessFactorizationStop[%d] should be < 1","messagePattern":"Last bitmapFullnessFactorizationStop\\[(.+?)\\] should be < 1","errorType":"validation","errorClass":"RE","httpStatus":null,"severity":"critical","filePath":"processing/src/main/java/org/apache/druid/segment/BitmapOffset.java","lineNumber":76,"sourceCode":"    if (new HashSet<>(Arrays.asList(stopsArray)).size() != stopsArray.length) {\n      throw new RE(\"Non unique bitmapFullnessFactorizationStops: \" + stopString);\n    }\n\n    BITMAP_FULLNESS_FACTORIZATION_STOPS = new double[stopsArray.length];\n    for (int i = 0; i < stopsArray.length; i++) {\n      String stop = stopsArray[i];\n      BITMAP_FULLNESS_FACTORIZATION_STOPS[i] = Double.parseDouble(stop);\n\n    }\n    Arrays.sort(BITMAP_FULLNESS_FACTORIZATION_STOPS);\n\n    double firstStop = BITMAP_FULLNESS_FACTORIZATION_STOPS[0];\n    if (Double.isNaN(firstStop) || firstStop <= 0.0) {\n      throw new RE(\"First bitmapFullnessFactorizationStop[%d] should be > 0\", firstStop);\n    }\n    double lastStop = BITMAP_FULLNESS_FACTORIZATION_STOPS[stopsArray.length - 1];\n    if (Double.isNaN(lastStop) || lastStop >= 1) {\n      throw new RE(\"Last bitmapFullnessFactorizationStop[%d] should be < 1\", lastStop);\n    }\n\n    String prevStop = \"0\";\n    FACTORIZED_FULLNESS = new String[stopsArray.length + 1];\n    for (int i = 0; i < stopsArray.length; i++) {\n      String stop = String.valueOf(BITMAP_FULLNESS_FACTORIZATION_STOPS[i]);\n      FACTORIZED_FULLNESS[i] = \"(\" + prevStop + \", \" + stop + \"]\";\n      prevStop = stop;\n    }\n    FACTORIZED_FULLNESS[stopsArray.length] = \"(\" + prevStop + \", 1)\";\n  }\n\n  /**\n   * Processing of queries with BitmapOffsets, whose Bitmaps has different factorized fullness (bucket), reported from\n   * this method, uses different copies of the same code, so JIT compiler analyzes and compiles the code for different\n   * factorized fullness separately. The goal is to capture frequency of abstraction usage in compressed bitmap\n   * algorithms, i. e.\n   *    - \"Zero sequence\" vs. \"Literal\" vs. \"One sequence\" in {@link org.apache.druid.extendedset.intset.ImmutableConciseSet}","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/BitmapOffset.java#L58-L94","documentation":"BitmapOffset also validates that the largest bitmapFullnessFactorizationStops value is strictly less than 1 (and not NaN), because a fullness stop of 1 or more would create an unbounded/degenerate factorization band. Violations throw RE 'Last bitmapFullnessFactorizationStop[%d] should be < 1' from the static initializer.","triggerScenarios":"Starting a JVM with -DbitmapFullnessFactorizationStops containing a value >= 1 or NaN as the largest entry, e.g. '0.2,1.0' or '0.2,Infinity'; checked after sorting in the static block.","commonSituations":"Ops assuming the range is [0,1] inclusive and setting 1.0 as the last stop; Infinity or NaN leaking from generated config; adapting stop lists from other tuning systems with different ranges.","solutions":["Change the largest stop to a double strictly below 1, e.g. 0.9 or 0.99.","Remove the -DbitmapFullnessFactorizationStops flag to use the built-in defaults.","Fix config generation to clamp stops to (0,1) exclusive.","Restart after correcting; failure occurs during class initialization."],"exampleFix":"// before\n-DbitmapFullnessFactorizationStops=0.2,1.0\n// after\n-DbitmapFullnessFactorizationStops=0.2,0.9","handlingStrategy":"validation","validationCode":"double last = parsed[parsed.length - 1]; // after sort\nif (Double.isNaN(last) || last >= 1.0) {\n  throw new IllegalStateException(\"last stop must be < 1\");\n}","typeGuard":"boolean validLastStop(List<Double> stops) {\n  List<Double> s = new ArrayList<>(stops);\n  Collections.sort(s);\n  return !Double.isNaN(s.get(s.size() - 1)) && s.get(s.size() - 1) < 1.0;\n}","tryCatchPattern":"try {\n  validateStops(prop);\n} catch (IllegalArgumentException e) {\n  log.error(e, \"bitmap stop >= 1 rejected; using defaults\");\n  prop = DEFAULT_FULLNESS_FACTORIZATION_STOPS;\n}","preventionTips":["Treat the stop range as open interval (0,1), never inclusive of 1","Clamp generated stops to e.g. [0.01, 0.99]","Guard templates against producing Infinity/NaN","Validate all JVM tuning flags in CI startup checks"],"tags":["java","jvm-properties","static-init","bitmap","value-out-of-range"],"backgroundTag":"value-out-of-range","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}