{"record":{"id":"52b417206101d626","repo":"hibernate/hibernate-orm","slug":"can-t-emulate-error-on-empty-clause-on-h2","errorCode":null,"errorMessage":"Can't emulate error on empty clause on H2","messagePattern":"Can't emulate error on empty clause on H2","errorType":"exception","errorClass":"QueryException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonQueryFunction.java","lineNumber":39,"sourceCode":" */\npublic class H2JsonQueryFunction extends JsonQueryFunction {\n\n\tpublic H2JsonQueryFunction(TypeConfiguration typeConfiguration) {\n\t\tsuper( typeConfiguration, false, true );\n\t}\n\n\t@Override\n\tprotected void render(\n\t\t\tSqlAppender sqlAppender,\n\t\t\tJsonQueryArguments arguments,\n\t\t\tReturnableType<?> returnType,\n\t\t\tSqlAstTranslator<?> walker) {\n\t\t// Json dereference errors by default if the JSON is invalid\n\t\tif ( arguments.errorBehavior() != null && arguments.errorBehavior() != JsonQueryErrorBehavior.ERROR ) {\n\t\t\tthrow new QueryException( \"Can't emulate on error clause on H2\" );\n\t\t}\n\t\tif ( arguments.emptyBehavior() == JsonQueryEmptyBehavior.ERROR ) {\n\t\t\tthrow new QueryException( \"Can't emulate error on empty clause on H2\" );\n\t\t}\n\t\tappendJsonQuery(\n\t\t\t\tsqlAppender,\n\t\t\t\targuments.jsonDocument(),\n\t\t\t\targuments.isJsonType(),\n\t\t\t\targuments.jsonPath(),\n\t\t\t\targuments.passingClause(),\n\t\t\t\targuments.wrapMode(),\n\t\t\t\targuments.emptyBehavior(),\n\t\t\t\twalker\n\t\t);\n\t}\n\n\tstatic void appendJsonQuery(\n\t\t\tSqlAppender sqlAppender,\n\t\t\tExpression jsonDocument,\n\t\t\tboolean isJsonType,\n\t\t\tExpression jsonPathExpression,","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonQueryFunction.java#L21-L57","documentation":"For json_query() on H2, ERROR ON EMPTY has no emulation: the dereference-based rendering naturally yields NULL for a missing path, and raising an error instead cannot be expressed in the emulation. The translator accepts NULL (the default) and the empty-array/empty-object variants, but throws when emptyBehavior() == JsonQueryEmptyBehavior.ERROR.","triggerScenarios":"HQL on the H2 dialect: select json_query(d.doc, '$.tags[*]' error on empty) from Document d. Only this strict form is rejected; null on empty and empty array/object on empty pass through.","commonSituations":"Strict-mode queries ported from Oracle or SQL Server where ERROR ON EMPTY is explicit; H2 unit tests starting to fail after a strictness clause was added for production semantics.","solutions":["Remove error on empty and let the default NULL ON EMPTY apply","Detect emptiness in application code by checking for a null result instead of asking the database to raise","Run these queries against the production database in tests (Testcontainers)","Use a native query if ERROR ON EMPTY semantics are mandatory"],"exampleFix":"// before - throws on H2\nselect json_query(d.doc, '$.tags[*]' error on empty) from Document d\n\n// after - default NULL ON EMPTY; check for null in Java\nselect json_query(d.doc, '$.tags[*]') from Document d","handlingStrategy":"validation","validationCode":"// Reject ERROR ON EMPTY for json_query on H2 before execution\nstatic void assertTranslatable(SessionFactory sf, String hql) {\n    if (sf.getJdbcServices().getDialect() instanceof org.hibernate.dialect.H2Dialect\n            && hql.toLowerCase().contains(\"error on empty\")) {\n        throw new IllegalArgumentException(\n            \"H2 json_query cannot emulate 'error on empty'; rely on the default NULL ON EMPTY\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql, String.class).getSingleResult();\n} catch (org.hibernate.QueryException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"error on empty clause on H2\")) {\n        // Retry with default NULL ON EMPTY and treat null as 'missing'\n        return session.createQuery(stripClause(hql, \"error on empty\"), String.class).getSingleResult();\n    }\n    throw e;\n}","preventionTips":["Check for a null result in application code instead of requesting ERROR ON EMPTY","Reserve strict empty/error clauses for databases you have verified support them","Keep a dialect-capability table in your repository layer for the JSON clause matrix"],"tags":["hibernate","h2","json","hql","json-query","sql-dialect","query-exception"],"backgroundTag":"json-on-empty-clause-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}