apache/druid · error · ISE
Unexpected NilColumnValueSelector
Error message
Unexpected NilColumnValueSelector
What it means
BloomFilterMergeAggregatorFactory.makeMergeAggregator() asserts that the selector for the field is not a NilColumnValueSelector (a selector that always returns null, e.g. for nonexistent columns). Since merge inputs should always carry serialized bloom filter values as empty filters rather than nulls, a nil selector violates the contract and throws IllegalStateException.
Solutions
- Fix the merge aggregator's fieldName to match the output column actually produced by the upstream bloom aggregation
- Ensure all segments/subqueries produce the bloom filter column (use default empty-filter output for missing data)
- Add exists-checks / use segment metadata to confirm column presence before merging
- Align schemas across segments so the bloom column is never absent
Example fix
// before
{"type": "bloomMerge", "name": "bf", "fieldName": "bf_out"} // bf_out missing from one subquery result
// after
{"type": "query", "query": {"queryType": "groupBy", "aggregations": [{"type": "bloom", "name": "bf_out", ...}]}}
// then merge with matching fieldName "bf_out" (verified present in every subquery result) Defensive patterns
Strategy: validation
Validate before calling
// Verify the merge field exists in all result sets before merging // e.g. inspect the subquery/broker result's column list for fieldName boolean fieldPresent = resultColumns.contains(mergeFactory.getFieldName());
Type guard
if (selector instanceof NilColumnValueSelector) { /* handle missing column: error or empty filter */ } Try / catch
try {
aggregator = mergeFactory.factorize(metricFactory);
} catch (IllegalStateException e) {
if (e.getMessage().contains("Unexpected NilColumnValueSelector")) {
// correct fieldName or add missing column upstream
} else throw e;
} Prevention
- Double-check 'fieldName' in bloomMerge specs matches the upstream aggregation output name
- Keep schemas consistent across segments and subqueries so the column is always present
- Validate query results for the column before broker-side merging
When it happens
Trigger: Calling factorize/factorizeBuffered on a BloomFilterMergeAggregatorFactory where the requested field name does not exist in the segment/result columns (Druid returns a nil selector), e.g. merging results where one side lacks the bloom column, or a typo'd field name in the merge aggregator spec.
Common situations: Broker-side merge of group-by/subquery results where a shard has no matching column; schema drift between segments; misconfigured merge aggregator 'fieldName' pointing to a non-existent output column.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- bf1Length does not match bf2Length
- Bloom filter aggregators are query-time only
- Bloom filter aggregators are query-time only
- Cannot create bloom filter
- Emit called unexpectedly before service start
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/765ce77fbbaea071.
Report an issue: GitHub.
Appendix: source
Thrown at extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/aggregation/bloom/BloomFilterMergeAggregatorFactory.java:77
{
return new CacheKeyBuilder(AggregatorUtil.BLOOM_FILTER_MERGE_CACHE_TYPE_ID)
.appendString(fieldName)
.appendInt(getMaxNumEntries())
.build();
}
@Override
public AggregatorFactory withName(String newName)
{
return new BloomFilterMergeAggregatorFactory(newName, fieldName, getMaxNumEntries());
}
private BloomFilterMergeAggregator makeMergeAggregator(ColumnSelectorFactory metricFactory)
{
final BaseNullableColumnValueSelector selector = metricFactory.makeColumnValueSelector(fieldName);
// null columns should be empty bloom filters by this point, so encountering a nil column in merge agg is unexpected
if (selector instanceof NilColumnValueSelector) {
throw new ISE("Unexpected NilColumnValueSelector");
}
return new BloomFilterMergeAggregator((ColumnValueSelector<ByteBuffer>) selector, getMaxNumEntries(), true);
}
}
View on GitHub (pinned to 9b90983fd2)