{"record":{"id":"c04e8adb923d3daa","repo":"apache/druid","slug":"bloomkfilters-are-not-compatible-for-merging-this","errorCode":null,"errorMessage":"BloomKFilters are not compatible for merging. this - %s that - %s","messagePattern":"BloomKFilters are not compatible for merging\\. this - (.+?) that - (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/filter/BloomKFilter.java","lineNumber":707,"sourceCode":"  }\n\n  @Override\n  public String toString()\n  {\n    return \"m: \" + m + \" k: \" + k;\n  }\n\n  /**\n   * Merge the specified bloom filter with current bloom filter.\n   *\n   * @param that - bloom filter to merge\n   */\n  public void merge(BloomKFilter that)\n  {\n    if (this != that && this.m == that.m && this.k == that.k) {\n      this.bitSet.putAll(that.bitSet);\n    } else {\n      throw new IllegalArgumentException(\"BloomKFilters are not compatible for merging.\" +\n                                         \" this - \" + this + \" that - \" + that);\n    }\n  }\n\n  public void reset()\n  {\n    this.bitSet.clear();\n  }\n\n  /**\n   * Bare metal bit set implementation. For performance reasons, this implementation does not check\n   * for index bounds nor expand the bit set size if the specified index is greater than the size.\n   */\n  public static class BitSet\n  {\n    private final long[] data;\n\n    public BitSet(long bits)","sourceCodeStart":689,"sourceCodeEnd":725,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/filter/BloomKFilter.java#L689-L725","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nBloomKFilter merged = new BloomKFilter(numRows); // task-specific\nmerged.merge(otherFilter); // may throw\n\n// after\nif (otherFilter != null && isCompatible(merged, otherFilter)) {\n  merged.merge(otherFilter);\n} else {\n  throw new ISE(\"Incompatible bloom filter: %s\", otherFilter);\n}","handlingStrategy":"validation","validationCode":"// Java: check m and k before merging\npublic static boolean canMerge(BloomKFilter a, BloomKFilter b) {\n  return a != null && b != null && a.getBitSize() == b.getBitSize() && a.getNumHashes() == b.getNumHashes();\n}","typeGuard":null,"tryCatchPattern":"try {\n  target.merge(that);\n} catch (IllegalArgumentException e) {\n  // log filter parameters from e.getMessage() and rebuild with matched m/k\n}","preventionTips":["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."],"tags":["bloom-filter","merge-compatibility","illegal-argument"],"backgroundTag":"incompatible-source-type","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}