apache/druid · error · IAE

Cannot create bloom filter %s for invalid column type [%s]

Error message

Cannot create bloom filter %s for invalid column type [%s]

What it means

factorizeInternal() switches on the column capabilities (type) of the field being aggregated. Bloom filters can only aggregate string-like or complex bloom-filter columns; a column with an unsupported type (e.g. long/double/numeric) hits the default branch and throws this IllegalArgumentException naming the column type.

Source

Thrown at extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/aggregation/bloom/BloomFilterAggregatorFactory.java:292

              columnFactory.makeColumnValueSelector(field.getDimension()),
              maxNumEntries,
              onHeap
          );
        case DOUBLE:
          return new DoubleBloomFilterAggregator(
              columnFactory.makeColumnValueSelector(field.getDimension()),
              maxNumEntries,
              onHeap
          );
        case COMPLEX:
          // in an ideal world, we would check complex type, but until then assume it's a bloom filter
          return new BloomFilterMergeAggregator(
              columnFactory.makeColumnValueSelector(field.getDimension()),
              maxNumEntries,
              onHeap
          );
        default:
          throw new IAE(
              "Cannot create bloom filter %s for invalid column type [%s]",
              onHeap ? "aggregator" : "buffer aggregator",
              capabilities.asTypeString()
          );
      }
    } else {
      // No column capabilities, try to guess based on selector type.
      BaseNullableColumnValueSelector selector = columnFactory.makeColumnValueSelector(field.getDimension());

      if (selector instanceof NilColumnValueSelector) {
        return new NoopBloomFilterAggregator(maxNumEntries, onHeap);
      } else if (selector instanceof DimensionSelector) {
        return new StringBloomFilterAggregator((DimensionSelector) selector, maxNumEntries, onHeap);
      } else {
        // Use fallback 'object' aggregator.
        return new ObjectBloomFilterAggregator(
            columnFactory.makeColumnValueSelector(field.getDimension()),
            maxNumEntries,

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Aggregate a STRING-typed column: cast or add a transform/expression in the query, e.g. use "type": "default" dimension with an expression like CAST(col AS STRING) via an ExpressionDimensionSpec
  2. Fix ingestion to store the column as string if bloom filtering on it is required
  3. Verify the dimension name points to the intended column and check its type via segment metadata query
  4. Use the SQL layer with BLOOM_FILTER_AGG and CAST(col, 'VARCHAR')

Example fix

// before
{"type": "bloom", "name": "bf", "field": {"type": "default", "dimension": "user_id_long"}} // numeric column
// after
{"type": "bloom", "name": "bf", "field": {"type": "expression", "expression": "CAST(user_id_long AS VARCHAR)", "dimension": "user_id_str"}}
Defensive patterns

Strategy: validation

Validate before calling

// Check column type before running the bloom aggregation (segment metadata query)
// SELECT column, dataType FROM sys.segments ... or use SegmentMetadataQuery; require VALUE_TYPE_STRING
boolean ok = "STRING".equals(capabilities.getType().toString());

Try / catch

try {
  aggregator = factory.factorize(selectorFactory);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("invalid column type")) {
    // re-plan query with a cast/expression dimension to STRING
  } else throw e;
}

Prevention

When it happens

Trigger: Running a query with a 'bloom' aggregator on a dimension whose underlying column type is not STRING (or the bloom-filter complex type), e.g. aggregating a numeric (long/double/float) column or a schemaless/mismatched column; calling factorize()/factorizeBuffered() on a ColumnSelectorFactory whose capabilities.asTypeString() reports VALUE_TYPE_NUMERIC or similar.

Common situations: Querying a numeric metric column with a bloom aggregator by mistake; schema evolved so the column is now numeric; typo'd dimension resolving to the wrong column; schemaless ingestion auto-detected numbers where strings were expected.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/58eac01422921a29. Report an issue: GitHub.