apache/druid · error · ExpressionValidationException

needs an integer as the second argument

Error message

needs an integer as the second argument

What it means

The REPEAT(string, n) expression function requires its second argument to be an exact integer (no fractional value after narrowing: yInt != y). A non-integral value is rejected; additionally n < 1 yields NULL rather than repeating.

Solutions

  1. Cast the second argument to an integral value: CAST(col AS BIGINT)
  2. Use FLOOR/CEIL or integer arithmetic when deriving the count from division
  3. Range-check the count to [1, 2147483647] before calling
  4. Treat n < 1 as NULL in your query logic (REPEAT returns NULL for those)

Example fix

// before: REPEAT(x, total/4) where total/4 = 2.5 -> throws
// after: REPEAT(x, CAST(FLOOR(total/4) AS BIGINT))
Defensive patterns

Strategy: validation

Validate before calling

if (!(count >= 1 && count <= Integer.MAX_VALUE && count == Math.floor((double) count))) {
  throw new IllegalArgumentException("REPEAT count must be a positive integer: " + count);
}

Type guard

static boolean validRepeatCount(long count) {
  return count >= 1 && count <= Integer.MAX_VALUE;
}

Prevention

When it happens

Trigger: REPEAT('x', 2.5) where the argument evaluates to a non-integral value, or any count not exactly representable as an int.

Common situations: DOUBLE-typed columns passed as the repeat count; counts derived from division producing fractions; user parameters with decimals.

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/86f096f6bdae0e53. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/math/expr/Function.java:3109

    @Override
    public String name()
    {
      return "repeat";
    }

    @Nullable
    @Override
    public ExpressionType getOutputType(Expr.InputBindingInspector inspector, List<Expr> args)
    {
      return ExpressionType.STRING;
    }

    @Override
    protected ExprEval eval(String x, long y)
    {
      int yInt = (int) y;
      if (yInt != y) {
        throw validationFailed("needs an integer as the second argument");
      }
      return ExprEval.ofString(y < 1 ? null : StringUtils.repeat(x, yInt));
    }
  }

  class LpadFunc implements Function
  {
    @Override
    public String name()
    {
      return "lpad";
    }

    @Override
    public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
    {
      String base = args.get(0).eval(bindings).asString();
      int len = args.get(1).eval(bindings).asInt();

View on GitHub (pinned to 9b90983fd2)