hibernate/hibernate-orm · error · FunctionArgumentException

json_object must have an even number of arguments, but found

Error message

json_object must have an even number of arguments, but found %d

What it means

json_object builds an object from key/value pairs, so it needs an even number of arguments. JsonObjectArgumentsValidator runs during SQM validation (query compile time) and throws this FunctionArgumentException when the count is odd. A trailing JSON null behavior element is excluded from the count before the parity check.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/dialect/function/json/JsonObjectArgumentsValidator.java:90

					final var expressionType = expression.getExpressionType();
					if ( expressionType != null && !isUnknownExpressionType( expressionType ) ) {
						final var mapping = expressionType.getSingleJdbcMapping();
						checkArgumentType(
								i,
								functionName,
								FunctionParameterType.STRING,
								mapping.getJdbcType(),
								mapping.getJavaTypeDescriptor().getJavaType()
						);
					}
				}
			}
		}
	}

	private void checkArgumentsCount(int size) {
		if ( ( size & 1 ) == 1 ) {
			throw new FunctionArgumentException(
					String.format(
							"json_object must have an even number of arguments, but found %d",
							size
					)
			);
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Count the arguments and add the missing value: json_object('a', 1, 'b', 2).
  2. Check the last pair: a missing value after the final key is the most common cause.
  3. When you append a JSON null behavior element, keep the key/value count even before it.
  4. Log the assembled argument list when you build calls dynamically, so the odd pair is visible.

Example fix

// before
select json_object('id', e.id, 'name') from Entity e

// after
select json_object('id', e.id, 'name', e.name) from Entity e
Defensive patterns

Strategy: validation

Validate before calling

// Validate pair count before you assemble the HQL call.
static String jsonObject(Map<String, Object> pairs) {
    if (pairs.size() * 2 % 2 != 0 || pairs.isEmpty()) {
        throw new IllegalArgumentException("json_object needs an even number of arguments");
    }
    StringBuilder sb = new StringBuilder("json_object(");
    boolean first = true;
    for (var e : pairs.entrySet()) {
        if (!first) sb.append(',');
        sb.append('\'').append(e.getKey()).append('\'').append(',').append(valueExpression(e.getValue()));
        first = false;
    }
    return sb.append(')').toString();
}
// Always build calls from key/value maps; never concatenate unpaired values.

Try / catch

try {
    return session.createQuery(hql).getResultList();
} catch (org.hibernate.query.sqm.produce.function.FunctionArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("even number of arguments")) {
        throw new IllegalArgumentException("json_object argument list lost a value: " + hql, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: An HQL call such as json_object('a', 1, 'b') passes three values. After the optional SqmJsonNullBehavior tail is discounted, (size & 1) == 1 and validation fails before any SQL is produced.

Common situations: Building json_object arguments in a loop and dropping the last value. Migrating hand-written SQL that used a different convention. Adding ABSENT ON NULL or NULL ON NULL as a trailing element and miscounting the pairs.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/ccb023bb344c2ab0. Report an issue: GitHub.