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.
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)
Solutions
- Edit jvm.config to remove the duplicated stop so all values are distinct.
- Use the default by deleting the -DbitmapFullnessFactorizationStops flag.
- Deduplicate the generated list in the config script (e.g. sort -u) before injecting it into JVM args.
- 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
- Deduplicate stop lists in config generation scripts
- Never hand-append a default stop to a custom list without checking
- Peer-review jvm.config tuning changes
- Validate the property in startup scripts before launching the JVM
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
- Empty bitmapFullnessFactorizationStops:
- First bitmapFullnessFactorizationStop[%d] should be > 0
- Last bitmapFullnessFactorizationStop[%d] should be < 1
- Only positive integers or zero can be added
- Cannot remove non Integer from integer BitSet
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/c24319ff020116d1.
Report an issue: GitHub.