apache/druid · error · IllegalArgumentException
BloomKFilters are not compatible for merging. this
Error message
BloomKFilters are not compatible for merging. this - %s that - %s
What it means
BloomKFilter.merge() only combines two filters built with identical bit-size (m) and hash-function count (k). If either parameter differs — or the filter is merged with itself through a wrong reference check path — the merge is rejected with this IllegalArgumentException, because the resulting bitset would be meaningless.
Solutions
- Check compatibility first: verify both filters expose the same m and k (use BloomKFilterHolder fields or the string from the exception) before merging.
- Standardize the numEntries (and fpp) parameter for the query/inclusion so all filters are built with identical size and hash count.
- Rebuild the offending filter(s) with the same parameters as the target filter, then retry the merge.
Example fix
// before
BloomKFilter merged = new BloomKFilter(numRows); // task-specific
merged.merge(otherFilter); // may throw
// after
if (otherFilter != null && isCompatible(merged, otherFilter)) {
merged.merge(otherFilter);
} else {
throw new ISE("Incompatible bloom filter: %s", otherFilter);
} Defensive patterns
Strategy: validation
Validate before calling
// Java: check m and k before merging
public static boolean canMerge(BloomKFilter a, BloomKFilter b) {
return a != null && b != null && a.getBitSize() == b.getBitSize() && a.getNumHashes() == b.getNumHashes();
} Try / catch
try {
target.merge(that);
} catch (IllegalArgumentException e) {
// log filter parameters from e.getMessage() and rebuild with matched m/k
} Prevention
- Always derive numEntries/fpp from a shared constant so all tasks build identical filters.
- Persist m and k alongside serialized filters and compare before aggregating.
- Add a pre-merge compatibility assert in aggregation code.
When it happens
Trigger: Calling bloomFilter.merge(other) where other was constructed with a different expected number of items (different m), a different numEntries/fpp yielding different k, or deserialized from data produced with different parameters.
Common situations: Merging bloom filters computed in different ingestion tasks with different numEntries settings; loading serialized filters from older data versions; aggregating filters across segments where per-segment parameters were auto-computed from different row counts.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- A-Not-B requires at least 1 sketch
- argument must be a LONG constant
- bf1Length does not match bf2Length
- Bloom filter aggregators are query-time only
- Bloom filter aggregators are query-time only
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/c04e8adb923d3daa.
Report an issue: GitHub.
Appendix: source
Thrown at extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/filter/BloomKFilter.java:707
}
@Override
public String toString()
{
return "m: " + m + " k: " + k;
}
/**
* Merge the specified bloom filter with current bloom filter.
*
* @param that - bloom filter to merge
*/
public void merge(BloomKFilter that)
{
if (this != that && this.m == that.m && this.k == that.k) {
this.bitSet.putAll(that.bitSet);
} else {
throw new IllegalArgumentException("BloomKFilters are not compatible for merging." +
" this - " + this + " that - " + that);
}
}
public void reset()
{
this.bitSet.clear();
}
/**
* Bare metal bit set implementation. For performance reasons, this implementation does not check
* for index bounds nor expand the bit set size if the specified index is greater than the size.
*/
public static class BitSet
{
private final long[] data;
public BitSet(long bits)View on GitHub (pinned to 9b90983fd2)