apache/druid · warning

Projected output type

Error message

Projected output type %s of expression %s does not match provided type %s

What it means

ExpressionVirtualColumn.capabilities compares the output type inferred by evaluating the Druid expression against the explicitly configured outputType. If they differ and neither side is numeric, it warns that the projected type does not match the configured one; the inferred type is used. For numeric mismatches it only logs at debug level.

Solutions

  1. Align the column's outputType with the expression's inferred type
  2. Update the expression so its result type matches the declared outputType
  3. Treat the warning as informational if numeric (inference still wins for numerics)
  4. Cast inside the expression (e.g. CAST(... AS VARCHAR)) to force the intended type

Example fix

// before
// ExpressionVirtualColumn.forExpression(DruidExpression.of(ColumnType.STRING, expr), "v0", null) where expr returns LONG
// after
// ExpressionVirtualColumn.forExpression(DruidExpression.of(ColumnType.LONG, expr), "v0", null)
// or cast: DruidExpression.of(ColumnType.STRING, "CAST(expr AS VARCHAR)")
Defensive patterns

Strategy: validation

Validate before calling

// Before configuring, infer the expression type and compare with declared outputType
ColumnType inferred = Expressions.inferType(factory, parsedExpr);
if (declaredOutputType != null && inferred != null && inferred.getType() != declaredOutputType.getType()) { /* fix spec */ }

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: An ExpressionVirtualColumn is configured with outputType (e.g. STRING) but the expression's inferred type differs (e.g. LONG or ARRAY), discovered when capabilities() is called during query planning.

Common situations: A user-specified outputType in the virtual column spec contradicts the expression, e.g. after editing the expression to return an array while keeping the old outputType, or a planner change altering inference.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/virtual/ExpressionVirtualColumn.java:312

  @Override
  public ColumnCapabilities capabilities(ColumnInspector inspector, String columnName)
  {
    if (isDirectAccess(inspector)) {
      return inspector.getColumnCapabilities(expression.parsed.get().getBindingIfIdentifier());
    }

    final ColumnType outputType = expression.outputType;

    final ExpressionPlan plan = ExpressionPlanner.plan(inspector, expression.parsed.get());
    final ColumnCapabilities inferred = plan.inferColumnCapabilities(outputType);
    // if we can infer the column capabilities from the expression plan, then use that
    if (inferred != null) {
      // explicit outputType is used as a hint, how did it compare to the planners inferred output type?
      if (outputType != null && inferred.getType() != outputType.getType()) {
        // if both sides are numeric, let it slide and log at debug level
        // but mismatches involving strings and arrays might be worth knowing about so warn
        if (!inferred.isNumeric() && !outputType.isNumeric()) {
          log.warn(
              "Projected output type %s of expression %s does not match provided type %s",
              inferred.asTypeString(),
              expression.expressionString,
              outputType
          );
        } else {
          log.debug(
              "Projected output type %s of expression %s does not match provided type %s",
              inferred.asTypeString(),
              expression.expressionString,
              outputType
          );
        }
      }
      return inferred;
    }

    // fallback to default capabilities

View on GitHub (pinned to 9b90983fd2)