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
- Count the arguments and add the missing value: json_object('a', 1, 'b', 2).
- Check the last pair: a missing value after the final key is the most common cause.
- When you append a JSON null behavior element, keep the key/value count even before it.
- 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
- Build json_object calls from a key/value map, not from a raw argument list.
- When you append a JSON null behavior element, count pairs before it.
- Prefer format json_object('k1', v1, 'k2', v2) with one pair per line in reviews.
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
- Can't emulate on error clause on CockroachDB
- Can't emulate on empty clause on CockroachDB
- CockroachDB json_value only support literal json paths, but
- JSON path [" + JsonPathHelper.toJsonPath( jsonPathElements )
- Can't emulate json_arrayagg filter clause when using 'null o
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/ccb023bb344c2ab0.
Report an issue: GitHub.