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

  1. Pass an expression with exactly one string dimension binding
  2. Fall back to ExpressionSelectors.supplierFromDimensionSelector / general expression selector for other shapes
  3. 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

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


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)