{"record":{"id":"765ce77fbbaea071","repo":"apache/druid","slug":"unexpected-nilcolumnvalueselector","errorCode":null,"errorMessage":"Unexpected NilColumnValueSelector","messagePattern":"Unexpected NilColumnValueSelector","errorType":"exception","errorClass":"ISE","httpStatus":null,"severity":"error","filePath":"extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/aggregation/bloom/BloomFilterMergeAggregatorFactory.java","lineNumber":77,"sourceCode":"  {\n    return new CacheKeyBuilder(AggregatorUtil.BLOOM_FILTER_MERGE_CACHE_TYPE_ID)\n        .appendString(fieldName)\n        .appendInt(getMaxNumEntries())\n        .build();\n  }\n\n  @Override\n  public AggregatorFactory withName(String newName)\n  {\n    return new BloomFilterMergeAggregatorFactory(newName, fieldName, getMaxNumEntries());\n  }\n\n  private BloomFilterMergeAggregator makeMergeAggregator(ColumnSelectorFactory metricFactory)\n  {\n    final BaseNullableColumnValueSelector selector = metricFactory.makeColumnValueSelector(fieldName);\n    // null columns should be empty bloom filters by this point, so encountering a nil column in merge agg is unexpected\n    if (selector instanceof NilColumnValueSelector) {\n      throw new ISE(\"Unexpected NilColumnValueSelector\");\n    }\n    return new BloomFilterMergeAggregator((ColumnValueSelector<ByteBuffer>) selector, getMaxNumEntries(), true);\n  }\n}\n","sourceCodeStart":59,"sourceCodeEnd":82,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/aggregation/bloom/BloomFilterMergeAggregatorFactory.java#L59-L82","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"type\": \"bloomMerge\", \"name\": \"bf\", \"fieldName\": \"bf_out\"} // bf_out missing from one subquery result\n// after\n{\"type\": \"query\", \"query\": {\"queryType\": \"groupBy\", \"aggregations\": [{\"type\": \"bloom\", \"name\": \"bf_out\", ...}]}}\n// then merge with matching fieldName \"bf_out\" (verified present in every subquery result)","handlingStrategy":"validation","validationCode":"// Verify the merge field exists in all result sets before merging\n// e.g. inspect the subquery/broker result's column list for fieldName\nboolean fieldPresent = resultColumns.contains(mergeFactory.getFieldName());","typeGuard":"if (selector instanceof NilColumnValueSelector) { /* handle missing column: error or empty filter */ }","tryCatchPattern":"try {\n  aggregator = mergeFactory.factorize(metricFactory);\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"Unexpected NilColumnValueSelector\")) {\n    // correct fieldName or add missing column upstream\n  } else throw e;\n}","preventionTips":["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"],"tags":["druid","bloom-filter","nil-selector","missing-column"],"backgroundTag":"resource-not-found","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"}