apache/druid · error · IllegalStateException

Only constant and single input string expressions currently…

Error message

Only constant and single input string expressions currently support dictionary encoded selectors

What it means

Dictionary-encoded (single-value dimension) vector selectors for expression virtual columns are only implemented for constant expressions and single-input scalar string expressions. Any other expression plan (multi-input, numeric output) hitting this path throws IllegalStateException, since only deferred-evaluation string selectors exist for this code path.

Solutions

  1. Cast/wrap the expression to string output or use a non-dictionary-encoded (value) selector path
  2. Set query context 'vectorize':'false' to force the non-vectorized engine
  3. Materialize the expression at ingest time as a real column and query that
  4. Upgrade Druid — newer versions support more expression vectorization cases

Example fix

// before
expression: "a + b" used directly as dimension (multi-input, numeric)
// after
expression: "CONCAT(CAST(a AS STRING), '-', CAST(b AS STRING))" // single/multi handled via non-dict path, or disable vectorization
Defensive patterns

Strategy: validation

Validate before calling

// inspect the expression plan before choosing a dict-encoded selector
boolean supported = plan.is(ExpressionPlan.Trait.CONSTANT)
  || (plan.is(ExpressionPlan.Trait.SINGLE_INPUT_SCALAR)
      && plan.getOutputType() != null && plan.getOutputType().is(ExprType.STRING));

Type guard

boolean dictUsable = plan.getOutputType() != null && plan.getOutputType().is(ExprType.STRING);

Try / catch

try { sel = makeSingleValueDimensionVectorSelector(...); } catch (IllegalStateException e) { sel = makeVectorValueSelector(...); /* value path */ }

Prevention

When it happens

Trigger: Vectorized query asks for a dictionary-encoded single-value dimension selector on an expression virtual column whose plan is not SINGLE_INPUT_SCALAR with STRING output (e.g. numeric expression, multi-column expression).

Common situations: Grouping on a numeric expression virtual column with vectorization on; expression virtual column combining two columns used as a dimension; older Druid versions with narrower expression vectorization support.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVectorSelectors.java:76

      VectorColumnSelectorFactory factory,
      Expr expression
  )
  {
    final ExpressionPlan plan = ExpressionPlanner.plan(factory, expression);
    Preconditions.checkArgument(plan.is(ExpressionPlan.Trait.VECTORIZABLE));
    // only constant expressions are currently supported, nothing else should get here

    if (plan.isConstant()) {
      String constant = plan.getExpression().eval(InputBindings.nilBindings()).asString();
      return ConstantVectorSelectors.singleValueDimensionVectorSelector(factory.getReadableVectorInspector(), constant);
    }
    if (plan.is(ExpressionPlan.Trait.SINGLE_INPUT_SCALAR) && (plan.getOutputType() != null && plan.getOutputType().is(ExprType.STRING))) {
      return new SingleStringInputDeferredEvaluationExpressionDimensionVectorSelector(
          factory.makeSingleValueDimensionSelector(DefaultDimensionSpec.of(plan.getSingleInputName())),
          plan.getExpression()
      );
    }
    throw new IllegalStateException("Only constant and single input string expressions currently support dictionary encoded selectors");
  }

  public static VectorValueSelector makeVectorValueSelector(
      VectorColumnSelectorFactory factory,
      Expr expression
  )
  {
    final ExpressionPlan plan = ExpressionPlanner.plan(factory, expression);
    Preconditions.checkArgument(plan.is(ExpressionPlan.Trait.VECTORIZABLE));

    if (plan.isConstant()) {
      return ConstantVectorSelectors.vectorValueSelector(
          factory.getReadableVectorInspector(),
          (Number) plan.getExpression().eval(InputBindings.nilBindings()).value()
      );
    }
    final Expr.VectorInputBinding bindings = createVectorBindings(plan.getAnalysis(), factory);
    final ExprVectorProcessor<?> processor = plan.getExpression().asVectorProcessor(bindings);

View on GitHub (pinned to 9b90983fd2)