{"record":{"id":"33354962b6831006","repo":"hibernate/hibernate-orm","slug":"h2-json-query-only-support-literal-json-paths-but","errorCode":null,"errorMessage":"H2 json_query only support literal json paths, but got \" + jsonPathExpression","messagePattern":"H2 json_query only support literal json paths, but got \" \\+ jsonPathExpression","errorType":"exception","errorClass":"QueryException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonQueryFunction.java","lineNumber":67,"sourceCode":"\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,\n\t\t\t@Nullable JsonPathPassingClause passingClause,\n\t\t\t@Nullable JsonQueryWrapMode wrapMode,\n\t\t\t@Nullable JsonQueryEmptyBehavior emptyBehavior,\n\t\t\tSqlAstTranslator<?> walker) {\n\t\tfinal String jsonPath;\n\t\ttry {\n\t\t\tjsonPath = walker.getLiteralValue( jsonPathExpression );\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new QueryException( \"H2 json_query only support literal json paths, but got \" + jsonPathExpression );\n\t\t}\n\t\tappendJsonQuery( sqlAppender, jsonDocument, isJsonType, jsonPath, passingClause, wrapMode, emptyBehavior, walker );\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\tString jsonPath,\n\t\t\t@Nullable JsonPathPassingClause passingClause,\n\t\t\t@Nullable JsonQueryWrapMode wrapMode,\n\t\t\t@Nullable JsonQueryEmptyBehavior emptyBehavior,\n\t\t\tSqlAstTranslator<?> walker) {\n\t\tif ( emptyBehavior == JsonQueryEmptyBehavior.EMPTY_ARRAY || emptyBehavior == JsonQueryEmptyBehavior.EMPTY_OBJECT ) {\n\t\t\tsqlAppender.appendSql( \"coalesce(\" );\n\t\t}\n\n\t\tif ( wrapMode == JsonQueryWrapMode.WITH_WRAPPER ) {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonQueryFunction.java#L49-L85","documentation":"The H2 json_query() emulation rewrites the SQL/JSON path into H2 dereference operators, which requires the concrete path text at translation time. When the path argument is a bind parameter or other non-literal expression, walker.getLiteralValue() fails and Hibernate rethrows it as this QueryException during SQL rendering.","triggerScenarios":"HQL on H2 with a non-literal json_query path: select json_query(d.doc, :path) from Document d, or a path produced by concatenation/function calls.","commonSituations":"Dynamic reporting where the extraction path is stored per customer or per tenant; H2 test profiles failing while the PostgreSQL production profile (whose emulation accepts parameter paths) passes.","solutions":["Inline the path as a literal: json_query(d.doc, '$.items[*]')","Parameterize parts inside a literal path with PASSING: json_query(d.doc, '$.items[$i]' passing :idx as i)","Fall back to a native H2 query for fully dynamic paths","Keep a whitelist of pre-validated literal-path queries"],"exampleFix":"// before - throws on H2\nselect json_query(d.doc, :path) from Document d\n\n// after - literal path with passing for the variable index\nselect json_query(d.doc, '$.items[$i]' passing :idx as i) from Document d","handlingStrategy":"validation","validationCode":"// Heuristic lint: json_query paths must be string literals on H2\nprivate static final Pattern PARAM_QUERY_PATH =\n    Pattern.compile(\"(?i)json_query\\\\s*\\\\([^,]+,\\\\s*:\\\\w+\");\n\nstatic void assertLiteralJsonPaths(String hql) {\n    if (PARAM_QUERY_PATH.matcher(hql).find()) {\n        throw new IllegalArgumentException(\n            \"json_query path must be a string literal on H2; use PASSING for variable parts\");\n    }\n}","typeGuard":"// Java predicate (type-guard analogue) for Criteria/SQM path expressions\nstatic boolean isLiteralPath(org.hibernate.query.sqm.tree.expression.SqmExpression<?> pathExpr) {\n    return pathExpr instanceof org.hibernate.query.sqm.tree.expression.SqmLiteral<?>;\n}","tryCatchPattern":"try {\n    return session.createQuery(hql, String.class).getResultList();\n} catch (org.hibernate.QueryException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"only support literal json paths\")) {\n        throw new IllegalArgumentException(\"Inline the json_query path as a literal: \" + hql, e);\n    }\n    throw e;\n}","preventionTips":["Keep json_query paths as literals; move variability into the PASSING clause","Do not accept raw user input as a JSON path on H2-based deployments","Exercise every json_* query under each supported dialect in CI"],"tags":["hibernate","h2","json","hql","json-query","json-path","bind-parameter"],"backgroundTag":"non-literal-json-path","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}