apache/druid · error · DruidException

must have an even number of arguments

Error message

must have an even number of arguments

What it means

Druid's JSON_OBJECT nested-data macro builds an object from alternating key/value arguments, so it requires an even argument count. Druid throws a validation failure at expression compilation when an odd number of arguments is passed, since at least one key would lack a value.

Source

Thrown at processing/src/main/java/org/apache/druid/query/expression/NestedDataExpressions.java:67

public class NestedDataExpressions
{
  private static ExpressionType JSON_ARRAY = ExpressionTypeFactory.getInstance().ofArray(ExpressionType.NESTED_DATA);

  public static class JsonObjectExprMacro implements ExprMacroTable.ExprMacro
  {
    public static final String NAME = "json_object";

    @Override
    public String name()
    {
      return NAME;
    }

    @Override
    public Expr apply(List<Expr> args)
    {
      if (args.size() % 2 != 0) {
        throw validationFailed("must have an even number of arguments");
      }

      class StructExpr extends ExprMacroTable.BaseScalarMacroFunctionExpr
      {
        public StructExpr(List<Expr> args)
        {
          super(JsonObjectExprMacro.this, args);
        }

        @Override
        public ExprEval eval(ObjectBinding bindings)
        {
          HashMap<String, Object> theMap = new HashMap<>();
          for (int i = 0; i < args.size(); i += 2) {
            ExprEval field = args.get(i).eval(bindings);
            ExprEval value = args.get(i + 1).eval(bindings);

            if (!field.type().is(ExprType.STRING)) {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Count the arguments and add the missing key or value so pairs are complete: JSON_OBJECT('a', 1, 'b', 2).
  2. If a pair is not needed, remove both its key and value arguments.
  3. In generated SQL, assert args.size() % 2 == 0 before emitting the JSON_OBJECT call to fail early in your own code.

Example fix

-- before
SELECT JSON_OBJECT('a', x, 'b') FROM t
-- after
SELECT JSON_OBJECT('a', x, 'b', y) FROM t
Defensive patterns

Strategy: validation

Validate before calling

// JS/TS before emitting SQL
if (pairs.length % 2 !== 0) throw new Error('JSON_OBJECT requires an even number of key/value arguments');

Type guard

function hasEvenArgs(args) { return Array.isArray(args) && args.length % 2 === 0; }

Try / catch

try {
  return runDruidQuery(query);
} catch (ExpressionValidationException e) {
  if (e.getMessage().contains("even number of arguments")) {
    throw new UserInputException("JSON_OBJECT arguments must come in key/value pairs");
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling JSON_OBJECT(k1, v1, k2) — any odd-sized argument list to the JSON_OBJECT expression macro in a Druid SQL query or native expression selector.

Common situations: Programmatic query builders that append a value but skip its key (or vice versa); hand-written SQL where a key/value pair was deleted or duplicated incompletely; refactoring that dropped a trailing argument.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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