apache/druid · error · ExpressionValidationException
does not accept types
Error message
does not accept %s types
What it means
A variadic expression function (GREATEST/LEAST-style accumulator) type-checks every argument against isValidType; any argument whose expression type is not accepted aborts the whole expression with this validation error naming the offending type.
Solutions
- Cast offending arguments to a valid type: CAST(col AS BIGINT) or CAST(col AS DOUBLE)
- Check the function's isValidType (numeric-only here) and remove non-numeric arguments
- Inspect column types via EXPLAIN PLAN; string-typed dimensions need explicit numeric casts
- Fix the ingestion schema so the column carries the intended numeric type
Example fix
// before: GREATEST(dim, 10) where dim is STRING -> throws // after: GREATEST(CAST(dim AS BIGINT), 10)
Defensive patterns
Strategy: type-guard
Validate before calling
for (ExpressionType t : argTypes) {
if (!(t.is(ExprType.LONG) || t.is(ExprType.DOUBLE))) {
throw new IllegalArgumentException("numeric args required, got " + t);
}
} Type guard
static boolean allNumeric(List<ExpressionType> types) {
return types.stream().allMatch(t -> t.is(ExprType.LONG) || t.is(ExprType.DOUBLE));
} Prevention
- Verify each operand's type via EXPLAIN PLAN
- CAST string dimensions before numeric functions
- Keep ingestion schemas numerically typed
- Avoid mixing strings into variadic numeric functions
When it happens
Trigger: Calling the function with a STRING, complex, or array argument when it accepts only numeric types, e.g. greatest('abc', 1).
Common situations: Mixed-type operands where one is a string-typed dimension; schema drift after ingestion changes a column from numeric to string; hand-written native expressions in filters/selectors.
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
- first argument should be a LONG or DOUBLE but got
- second argument should be a LONG but got
- argument should be an identifier expression. Use array()…
- Cannot cast [ ] to [ ] (Types.InvalidCastException from…
- Cannot find strategy for type
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/eb79fcd316237236.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/math/expr/Function.java:671
}
@Override
public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
{
if (args.isEmpty()) {
return ExprEval.ofLong(null);
}
// evaluate arguments and collect output type
List<ExprEval<?>> evals = new ArrayList<>();
ExpressionType outputType = ExpressionType.LONG;
for (Expr expr : args) {
ExprEval<?> exprEval = expr.eval(bindings);
ExpressionType exprType = exprEval.type();
if (!isValidType(exprType)) {
throw validationFailed("does not accept %s types", exprType);
}
outputType = ExpressionTypeConversion.function(outputType, exprType);
if (exprEval.value() != null) {
evals.add(exprEval);
}
}
if (evals.isEmpty()) {
// The GREATEST/LEAST functions are not in the SQL standard. Emulate the behavior of postgres (return null if
// all expressions are null, otherwise skip null values) since it is used as a base for a wide number of
// databases. This also matches the behavior the long/double greatest/least post aggregators. Some other
// databases (e.g., MySQL) return null if any expression is null.
// https://www.postgresql.org/docs/9.5/functions-conditional.html
// https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_least
return ExprEval.ofType(outputType, null);
}
View on GitHub (pinned to 9b90983fd2)