{"record":{"id":"eb79fcd316237236","repo":"apache/druid","slug":"does-not-accept-s-types","errorCode":null,"errorMessage":"does not accept %s types","messagePattern":"does not accept (.+?) types","errorType":"validation","errorClass":"ExpressionValidationException","httpStatus":400,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/math/expr/Function.java","lineNumber":671,"sourceCode":"    }\n\n    @Override\n    public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)\n    {\n      if (args.isEmpty()) {\n        return ExprEval.ofLong(null);\n      }\n\n      // evaluate arguments and collect output type\n      List<ExprEval<?>> evals = new ArrayList<>();\n      ExpressionType outputType = ExpressionType.LONG;\n\n      for (Expr expr : args) {\n        ExprEval<?> exprEval = expr.eval(bindings);\n        ExpressionType exprType = exprEval.type();\n\n        if (!isValidType(exprType)) {\n          throw validationFailed(\"does not accept %s types\", exprType);\n        }\n        outputType = ExpressionTypeConversion.function(outputType, exprType);\n\n        if (exprEval.value() != null) {\n          evals.add(exprEval);\n        }\n      }\n\n      if (evals.isEmpty()) {\n        // The GREATEST/LEAST functions are not in the SQL standard. Emulate the behavior of postgres (return null if\n        // all expressions are null, otherwise skip null values) since it is used as a base for a wide number of\n        // databases. This also matches the behavior the long/double greatest/least post aggregators. Some other\n        // databases (e.g., MySQL) return null if any expression is null.\n        // https://www.postgresql.org/docs/9.5/functions-conditional.html\n        // https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_least\n        return ExprEval.ofType(outputType, null);\n      }\n","sourceCodeStart":653,"sourceCodeEnd":689,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/math/expr/Function.java#L653-L689","documentation":"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.","triggerScenarios":"Calling the function with a STRING, complex, or array argument when it accepts only numeric types, e.g. greatest('abc', 1).","commonSituations":"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.","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"],"exampleFix":"// before: GREATEST(dim, 10) where dim is STRING -> throws\n// after: GREATEST(CAST(dim AS BIGINT), 10)","handlingStrategy":"type-guard","validationCode":"for (ExpressionType t : argTypes) {\n  if (!(t.is(ExprType.LONG) || t.is(ExprType.DOUBLE))) {\n    throw new IllegalArgumentException(\"numeric args required, got \" + t);\n  }\n}","typeGuard":"static boolean allNumeric(List<ExpressionType> types) {\n  return types.stream().allMatch(t -> t.is(ExprType.LONG) || t.is(ExprType.DOUBLE));\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["druid","expressions","argument-type"],"backgroundTag":"type-mismatch","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"}