{"record":{"id":"ccb023bb344c2ab0","repo":"hibernate/hibernate-orm","slug":"json-object-must-have-an-even-number-of-arguments","errorCode":null,"errorMessage":"json_object must have an even number of arguments, but found %d","messagePattern":"json_object must have an even number of arguments, but found (.+?)","errorType":"validation","errorClass":"FunctionArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/json/JsonObjectArgumentsValidator.java","lineNumber":90,"sourceCode":"\t\t\t\t\tfinal var expressionType = expression.getExpressionType();\n\t\t\t\t\tif ( expressionType != null && !isUnknownExpressionType( expressionType ) ) {\n\t\t\t\t\t\tfinal var mapping = expressionType.getSingleJdbcMapping();\n\t\t\t\t\t\tcheckArgumentType(\n\t\t\t\t\t\t\t\ti,\n\t\t\t\t\t\t\t\tfunctionName,\n\t\t\t\t\t\t\t\tFunctionParameterType.STRING,\n\t\t\t\t\t\t\t\tmapping.getJdbcType(),\n\t\t\t\t\t\t\t\tmapping.getJavaTypeDescriptor().getJavaType()\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void checkArgumentsCount(int size) {\n\t\tif ( ( size & 1 ) == 1 ) {\n\t\t\tthrow new FunctionArgumentException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\"json_object must have an even number of arguments, but found %d\",\n\t\t\t\t\t\t\tsize\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n}\n","sourceCodeStart":72,"sourceCodeEnd":99,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/json/JsonObjectArgumentsValidator.java#L72-L99","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nselect json_object('id', e.id, 'name') from Entity e\n\n// after\nselect json_object('id', e.id, 'name', e.name) from Entity e","handlingStrategy":"validation","validationCode":"// Validate pair count before you assemble the HQL call.\nstatic String jsonObject(Map<String, Object> pairs) {\n    if (pairs.size() * 2 % 2 != 0 || pairs.isEmpty()) {\n        throw new IllegalArgumentException(\"json_object needs an even number of arguments\");\n    }\n    StringBuilder sb = new StringBuilder(\"json_object(\");\n    boolean first = true;\n    for (var e : pairs.entrySet()) {\n        if (!first) sb.append(',');\n        sb.append('\\'').append(e.getKey()).append('\\'').append(',').append(valueExpression(e.getValue()));\n        first = false;\n    }\n    return sb.append(')').toString();\n}\n// Always build calls from key/value maps; never concatenate unpaired values.","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql).getResultList();\n} catch (org.hibernate.query.sqm.produce.function.FunctionArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"even number of arguments\")) {\n        throw new IllegalArgumentException(\"json_object argument list lost a value: \" + hql, e);\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["hibernate","json","json-object","argument-validation","hql"],"backgroundTag":"json-object-argument-count-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}