{"record":{"id":"211c308c94f06630","repo":"apache/druid","slug":"only-constant-and-single-input-string-expressions","errorCode":null,"errorMessage":"Only constant and single input string expressions currently support dictionary encoded selectors","messagePattern":"Only constant and single input string expressions currently support dictionary encoded selectors","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVectorSelectors.java","lineNumber":76,"sourceCode":"      VectorColumnSelectorFactory factory,\n      Expr expression\n  )\n  {\n    final ExpressionPlan plan = ExpressionPlanner.plan(factory, expression);\n    Preconditions.checkArgument(plan.is(ExpressionPlan.Trait.VECTORIZABLE));\n    // only constant expressions are currently supported, nothing else should get here\n\n    if (plan.isConstant()) {\n      String constant = plan.getExpression().eval(InputBindings.nilBindings()).asString();\n      return ConstantVectorSelectors.singleValueDimensionVectorSelector(factory.getReadableVectorInspector(), constant);\n    }\n    if (plan.is(ExpressionPlan.Trait.SINGLE_INPUT_SCALAR) && (plan.getOutputType() != null && plan.getOutputType().is(ExprType.STRING))) {\n      return new SingleStringInputDeferredEvaluationExpressionDimensionVectorSelector(\n          factory.makeSingleValueDimensionSelector(DefaultDimensionSpec.of(plan.getSingleInputName())),\n          plan.getExpression()\n      );\n    }\n    throw new IllegalStateException(\"Only constant and single input string expressions currently support dictionary encoded selectors\");\n  }\n\n  public static VectorValueSelector makeVectorValueSelector(\n      VectorColumnSelectorFactory factory,\n      Expr expression\n  )\n  {\n    final ExpressionPlan plan = ExpressionPlanner.plan(factory, expression);\n    Preconditions.checkArgument(plan.is(ExpressionPlan.Trait.VECTORIZABLE));\n\n    if (plan.isConstant()) {\n      return ConstantVectorSelectors.vectorValueSelector(\n          factory.getReadableVectorInspector(),\n          (Number) plan.getExpression().eval(InputBindings.nilBindings()).value()\n      );\n    }\n    final Expr.VectorInputBinding bindings = createVectorBindings(plan.getAnalysis(), factory);\n    final ExprVectorProcessor<?> processor = plan.getExpression().asVectorProcessor(bindings);","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVectorSelectors.java#L58-L94","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Cast/wrap the expression to string output or use a non-dictionary-encoded (value) selector path","Set query context 'vectorize':'false' to force the non-vectorized engine","Materialize the expression at ingest time as a real column and query that","Upgrade Druid — newer versions support more expression vectorization cases"],"exampleFix":"// before\nexpression: \"a + b\" used directly as dimension (multi-input, numeric)\n// after\nexpression: \"CONCAT(CAST(a AS STRING), '-', CAST(b AS STRING))\" // single/multi handled via non-dict path, or disable vectorization","handlingStrategy":"validation","validationCode":"// inspect the expression plan before choosing a dict-encoded selector\nboolean supported = plan.is(ExpressionPlan.Trait.CONSTANT)\n  || (plan.is(ExpressionPlan.Trait.SINGLE_INPUT_SCALAR)\n      && plan.getOutputType() != null && plan.getOutputType().is(ExprType.STRING));","typeGuard":"boolean dictUsable = plan.getOutputType() != null && plan.getOutputType().is(ExprType.STRING);","tryCatchPattern":"try { sel = makeSingleValueDimensionVectorSelector(...); } catch (IllegalStateException e) { sel = makeVectorValueSelector(...); /* value path */ }","preventionTips":["Keep expression virtual columns used as dimensions single-input and string-output","Materialize complex multi-input expressions as real columns at ingest","Set 'vectorize':'false' when grouping on numeric expression columns"],"tags":["vectorization","expression","virtual-column","unsupported"],"backgroundTag":"unsupported-operation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}