apache/druid · error · DruidException

argument must be a literal

Error message

%s argument must be a literal

What it means

A NamedFunction requires a specific argument to be a compile-time literal (e.g. a format string or timezone), but a non-literal expression was supplied. validationHelperCheckArgIsLiteral checks Expr.isLiteral() and throws naming the argument.

Solutions

  1. Inline the value as a quoted literal string/number
  2. Pre-compute the value outside the expression
  3. If dynamism is required, choose a different function that accepts non-literal arguments

Example fix

// before
time_format(ts, tz_col)
// after
time_format(ts, 'America/Los_Angeles')
Defensive patterns

Strategy: validation

Validate before calling

if (!(argExpr instanceof LiteralExpr || argExpr.isLiteral())) { throw new IllegalArgumentException(argName + " must be a compile-time literal"); }

Type guard

boolean isLiteralArg(Expr e) { return e != null && e.isLiteral(); }

Try / catch

try { expr = Parser.parse(exprString); } catch (ExpressionValidationException e) { // prompt user to inline the literal value }

Prevention

When it happens

Trigger: Passing a column reference or computed expression where the function demands a literal, e.g. TIME_FORMAT(col, someColumn) or LIKE-style functions requiring a literal pattern argument.

Common situations: Users expecting function parameters to accept dynamic values; query builders binding runtime values into positions reserved for literals.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/math/expr/NamedFunction.java:125

        satisfied = true;
        break;
      }
    }
    if (!satisfied) {
      throw validationFailed(
          "requires %s arguments",
          Strings.join(" or ", () -> Arrays.stream(counts).mapToObj(String::valueOf).iterator())
      );
    }
  }

  /**
   * Helper method for implementors performing validation to check that an argument is a literal
   */
  default void validationHelperCheckArgIsLiteral(Expr arg, String argName)
  {
    if (!arg.isLiteral()) {
      throw validationFailed(
          "%s argument must be a literal",
          argName
      );
    }
  }

  /**
   * Helper method for implementors performing validation to check that the argument list is some expected size.
   *
   * The parser decomposes a function like 'fold((x, acc) -> x + acc, col, 0)' into the {@link LambdaExpr}
   * '(x, acc) -> x + acc' and the list of arguments, ['col', 0], and so does not include the {@link LambdaExpr} here.
   * To compensate for this, the error message will indicate that at least count + 1 arguments are required to count
   * the lambda.
   */
  default void validationHelperCheckArgumentCount(LambdaExpr lambdaExpr, List<Expr> args, int count)
  {
    if (args.size() != count) {
      throw validationFailed("requires %s arguments", count + 1);

View on GitHub (pinned to 9b90983fd2)