apache/druid · error · IllegalStateException
Selector must have a dictionary
Error message
Selector must have a dictionary
What it means
The per-dictionary-value cache in SingleStringInputCachingExpressionColumnValueSelector is sized by selector.getValueCardinality(); if the underlying dimension selector cannot report cardinality (CARDINALITY_UNKNOWN, e.g. a non-dictionary-encoded or grouped/unknown selector) the cache cannot be built and construction fails with ISE.
Source
Thrown at processing/src/main/java/org/apache/druid/segment/virtual/SingleStringInputCachingExpressionColumnValueSelector.java:74
final Expr expression,
@Nullable final RowIdSupplier rowIdSupplier
)
{
super(rowIdSupplier);
// Verify expression has just one binding.
if (expression.analyzeInputs().getRequiredBindings().size() != 1) {
throw new ISE("Expected expression with just one binding");
}
this.selector = Preconditions.checkNotNull(selector, "selector");
this.expression = Preconditions.checkNotNull(expression, "expression");
final Supplier<Object> inputSupplier = ExpressionSelectors.supplierFromDimensionSelector(selector, false, false);
this.bindings = InputBindings.forInputSupplier(ExpressionType.STRING, inputSupplier);
if (selector.getValueCardinality() == DimensionDictionarySelector.CARDINALITY_UNKNOWN) {
throw new ISE("Selector must have a dictionary");
} else if (selector.getValueCardinality() <= CACHE_SIZE) {
arrayEvalCache = new ExprEval[selector.getValueCardinality()];
lruEvalCache = null;
} else {
arrayEvalCache = null;
lruEvalCache = new LruEvalCache(expression, bindings);
}
}
@Override
public void inspectRuntimeShape(final RuntimeShapeInspector inspector)
{
super.inspectRuntimeShape(inspector);
inspector.visit("selector", selector);
inspector.visit("expression", expression);
}
@OverrideView on GitHub (pinned to 9b90983fd2)
Solutions
- Use a dictionary-encoded dimension selector (nameLookupPossibleInAdvance with known cardinality)
- Force dictionary encoding for the column at ingestion time
- Use the deferred-evaluation (LruEvalCache / SingleStringInputDeferredEvaluationExpression*) selector instead, which doesn't need cardinality
- Check cardinality before choosing the caching selector in custom factory code
Example fix
// before
new SingleStringInputCachingExpressionColumnValueSelector(unknownCardinalitySelector, expr)
// after
if (sel.getValueCardinality() == CARDINALITY_UNKNOWN) {
return new SingleStringInputDeferredEvaluationExpressionColumnValueSelector(sel, expr, ...);
} Defensive patterns
Strategy: type-guard
Validate before calling
boolean cacheable = sel.getValueCardinality() != DimensionDictionarySelector.CARDINALITY_UNKNOWN; return cacheable ? cachingSelector(sel, expr) : deferredSelector(sel, expr);
Type guard
boolean hasDictionary(DimensionDictionarySelector sel) {
return sel.getValueCardinality() != CARDINALITY_UNKNOWN;
} Try / catch
try {
return new SingleStringInputCachingExpressionColumnValueSelector(sel, expr, ...);
} catch (ISE e) {
return new SingleStringInputDeferredEvaluationExpressionColumnValueSelector(sel, expr, ...);
} Prevention
- Check getValueCardinality() before choosing caching vs deferred selectors
- Ensure columns are dictionary-encoded when relying on dictionary-based optimizations
- Handle non-dictionary columns in custom selector factories
When it happens
Trigger: Wrapping a string dimension selector whose getValueCardinality() returns DimensionDictionarySelector.CARDINALITY_UNKNOWN — typical with non-dictionary string columns, unknown cardinality selectors, or selectors that cannot do name lookup in advance.
Common situations: Running caching expression selectors over non-dictionary-encoded dimensions, or after ingestion changes where a column lost its dictionary encoding; also hits custom selector implementations that report unknown cardinality.
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
- Selector of class[%s] does not have a dictionary, cannot use
- Selector of class[%s] does not have a dictionary, cannot use
- attempt to get long[] from string[] only scalar binding
- attempt to get double[] from string[] only scalar binding
- attempt to get boolean[] null vector from string[] only scal
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/ad0e5303500723ba.
Report an issue: GitHub.