apache/druid · critical · RE

Non unique bitmapFullnessFactorizationStops:

Error message

Non unique bitmapFullnessFactorizationStops: 

What it means

The static initializer of BitmapOffset validates that the comma-separated bitmapFullnessFactorizationStops system property contains unique values. If the parsed stop list has duplicates (set size differs from array length), it throws RE 'Non unique bitmapFullnessFactorizationStops: ' echoing the raw string. This happens once per JVM at class initialization.

Solutions

  1. Edit jvm.config to remove the duplicated stop so all values are distinct.
  2. Use the default by deleting the -DbitmapFullnessFactorizationStops flag.
  3. Deduplicate the generated list in the config script (e.g. sort -u) before injecting it into JVM args.
  4. Restart the service after the fix; the exception aborts class loading.

Example fix

// before
-DbitmapFullnessFactorizationStops=0.2,0.5,0.2
// after
-DbitmapFullnessFactorizationStops=0.2,0.5,0.8
Defensive patterns

Strategy: validation

Validate before calling

String[] stops = prop.split(",");
if (new HashSet<>(Arrays.asList(stops)).size() != stops.length) {
  throw new IllegalStateException("duplicate bitmapFullnessFactorizationStops");
}

Type guard

boolean uniqueStops(String prop) {
  String[] s = prop.split(",");
  return new HashSet<>(Arrays.asList(s)).size() == s.length;
}

Try / catch

try {
  config.validateBitmapStops();
} catch (RuntimeException e) {
  log.error(e, "invalid bitmapFullnessFactorizationStops, falling back to default");
}

Prevention

When it happens

Trigger: Launching a Druid process with -DbitmapFullnessFactorizationStops containing a repeated value, e.g. '0.2,0.5,0.2' — detected by comparing HashSet size to array length in the static block.

Common situations: Hand-edited jvm.config tuning values that duplicate a stop; scripted config generation appending a default stop that already exists in a custom list; typo'd copies of the default stop list.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

  private static final int INVALID_VALUE = -1;

  /**
   * Currently the default stops are not consciously optimized for the goals described in {@link #factorizeFullness}.
   * They are chosen intuitively. There was no experimentation with different bitmapFullnessFactorizationStops.
   * Experimentation and performance feedback with a different set of stops is welcome.
   */
  private static final String DEFAULT_FULLNESS_FACTORIZATION_STOPS = "0.01,0.1,0.3,0.5,0.7,0.9,0.99";
  private static final double[] BITMAP_FULLNESS_FACTORIZATION_STOPS;
  private static final String[] FACTORIZED_FULLNESS;

  static {
    String stopString = System.getProperty("bitmapFullnessFactorizationStops", DEFAULT_FULLNESS_FACTORIZATION_STOPS);
    String[] stopsArray = stopString.split(",");
    if (stopsArray.length == 0) {
      throw new RE("Empty bitmapFullnessFactorizationStops: " + stopString);
    }
    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);
    }

View on GitHub (pinned to 9b90983fd2)