apache/druid · error · IllegalStateException
Expected expression with just one binding
Error message
Expected expression with just one binding
What it means
Identical single-binding constraint as the long-input variant: SingleStringInputCachingExpressionColumnValueSelector caches string expression evaluations per dictionary value, which is only valid when the expression depends on exactly one binding. Any other binding count causes an ISE in the constructor.
Solutions
- Pass an expression with exactly one string dimension binding
- Fall back to ExpressionSelectors.supplierFromDimensionSelector / general expression selector for other shapes
- Assert bindings count in your factory before choosing this selector
Example fix
// before new SingleStringInputCachingExpressionColumnValueSelector(sel, expr(concat(a, b))) // after new SingleStringInputCachingExpressionColumnValueSelector(sel, expr(upper(a))) // single binding
Defensive patterns
Strategy: validation
Validate before calling
if (expr.analyzeInputs().getRequiredBindings().size() != 1) {
// route to general expression selector instead
} Type guard
boolean isSingleStringBinding(Expr e) {
return e.analyzeInputs().getRequiredBindings().size() == 1;
} Try / catch
try {
return new SingleStringInputCachingExpressionColumnValueSelector(sel, expr, useLru, rowIdSupplier);
} catch (ISE e) {
return generalExpressionSelector(sel, expr, rowIdSupplier);
} Prevention
- Verify binding count before constructing single-input selectors
- Use ExpressionSelectors factory methods rather than instantiating selectors directly
- Keep expressions on single virtual columns when intending cached evaluation
When it happens
Trigger: Constructor invoked with an Expr whose required bindings size is not exactly 1, e.g. expression over two dimensions or a constant.
Common situations: Manually composing expression selectors in custom code, or engine routing bugs where a multi-column expression is handed to a single-input selector factory.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Expected expression with just one binding
- attempt to get boolean[] null vector from string[] only…
- attempt to get double[] from string[] only scalar binding
- attempt to get long[] from string[] only scalar binding
- Can only handle [ ], got [ ]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/64247039e6708c20.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/segment/virtual/SingleStringInputCachingExpressionColumnValueSelector.java:64
private final DimensionSelector selector;
private final Expr expression;
private final Expr.ObjectBinding bindings;
@Nullable
private final ExprEval[] arrayEvalCache;
@Nullable
private final LruEvalCache lruEvalCache;
public SingleStringInputCachingExpressionColumnValueSelector(
final DimensionSelector selector,
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);
}
}View on GitHub (pinned to 9b90983fd2)