apache/druid · critical · RE

Last bitmapFullnessFactorizationStop[%d] should be < 1

Error message

Last bitmapFullnessFactorizationStop[%d] should be < 1

What it means

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.

Source

Thrown at processing/src/main/java/org/apache/druid/segment/BitmapOffset.java:76

    if (new HashSet<>(Arrays.asList(stopsArray)).size() != stopsArray.length) {
      throw new RE("Non unique bitmapFullnessFactorizationStops: " + stopString);
    }

    BITMAP_FULLNESS_FACTORIZATION_STOPS = new double[stopsArray.length];
    for (int i = 0; i < stopsArray.length; i++) {
      String stop = stopsArray[i];
      BITMAP_FULLNESS_FACTORIZATION_STOPS[i] = Double.parseDouble(stop);

    }
    Arrays.sort(BITMAP_FULLNESS_FACTORIZATION_STOPS);

    double firstStop = BITMAP_FULLNESS_FACTORIZATION_STOPS[0];
    if (Double.isNaN(firstStop) || firstStop <= 0.0) {
      throw new RE("First bitmapFullnessFactorizationStop[%d] should be > 0", firstStop);
    }
    double lastStop = BITMAP_FULLNESS_FACTORIZATION_STOPS[stopsArray.length - 1];
    if (Double.isNaN(lastStop) || lastStop >= 1) {
      throw new RE("Last bitmapFullnessFactorizationStop[%d] should be < 1", lastStop);
    }

    String prevStop = "0";
    FACTORIZED_FULLNESS = new String[stopsArray.length + 1];
    for (int i = 0; i < stopsArray.length; i++) {
      String stop = String.valueOf(BITMAP_FULLNESS_FACTORIZATION_STOPS[i]);
      FACTORIZED_FULLNESS[i] = "(" + prevStop + ", " + stop + "]";
      prevStop = stop;
    }
    FACTORIZED_FULLNESS[stopsArray.length] = "(" + prevStop + ", 1)";
  }

  /**
   * Processing of queries with BitmapOffsets, whose Bitmaps has different factorized fullness (bucket), reported from
   * this method, uses different copies of the same code, so JIT compiler analyzes and compiles the code for different
   * factorized fullness separately. The goal is to capture frequency of abstraction usage in compressed bitmap
   * algorithms, i. e.
   *    - "Zero sequence" vs. "Literal" vs. "One sequence" in {@link org.apache.druid.extendedset.intset.ImmutableConciseSet}

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Change the largest stop to a double strictly below 1, e.g. 0.9 or 0.99.
  2. Remove the -DbitmapFullnessFactorizationStops flag to use the built-in defaults.
  3. Fix config generation to clamp stops to (0,1) exclusive.
  4. Restart after correcting; failure occurs during class initialization.

Example fix

// before
-DbitmapFullnessFactorizationStops=0.2,1.0
// after
-DbitmapFullnessFactorizationStops=0.2,0.9
Defensive patterns

Strategy: validation

Validate before calling

double last = parsed[parsed.length - 1]; // after sort
if (Double.isNaN(last) || last >= 1.0) {
  throw new IllegalStateException("last stop must be < 1");
}

Type guard

boolean validLastStop(List<Double> stops) {
  List<Double> s = new ArrayList<>(stops);
  Collections.sort(s);
  return !Double.isNaN(s.get(s.size() - 1)) && s.get(s.size() - 1) < 1.0;
}

Try / catch

try {
  validateStops(prop);
} catch (IllegalArgumentException e) {
  log.error(e, "bitmap stop >= 1 rejected; using defaults");
  prop = DEFAULT_FULLNESS_FACTORIZATION_STOPS;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/23437606292f3ac4. Report an issue: GitHub.