{"record":{"id":"07e541017c1c7a81","repo":"hibernate/hibernate-orm","slug":"h2-json-value-only-support-literal-json-paths-but","errorCode":null,"errorMessage":"H2 json_value only support literal json paths, but got \" + arguments.jsonPath()","messagePattern":"H2 json_value only support literal json paths, but got \" \\+ arguments\\.jsonPath\\(\\)","errorType":"exception","errorClass":"QueryException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonExistsFunction.java","lineNumber":38,"sourceCode":"\t\tsuper( typeConfiguration, true, true );\n\t}\n\n\t@Override\n\tprotected void render(\n\t\t\tSqlAppender sqlAppender,\n\t\t\tJsonExistsArguments 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() != JsonExistsErrorBehavior.ERROR ) {\n\t\t\tthrow new QueryException( \"Can't emulate on error clause on H2\" );\n\t\t}\n\t\tfinal String jsonPath;\n\t\ttry {\n\t\t\tjsonPath = walker.getLiteralValue( arguments.jsonPath() );\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new QueryException( \"H2 json_value only support literal json paths, but got \" + arguments.jsonPath() );\n\t\t}\n\t\targuments.jsonDocument().accept( walker );\n\t\tsqlAppender.appendSql( \" is not null and \" );\n\t\tH2JsonValueFunction.renderJsonPath(\n\t\t\t\tsqlAppender,\n\t\t\t\targuments.jsonDocument(),\n\t\t\t\targuments.isJsonType(),\n\t\t\t\twalker,\n\t\t\t\tjsonPath,\n\t\t\t\targuments.passingClause()\n\t\t);\n\t\tsqlAppender.appendSql( \" is not null\" );\n\t}\n}\n","sourceCodeStart":20,"sourceCodeEnd":53,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonExistsFunction.java#L20-L53","documentation":"The H2 json_exists() emulation must rewrite the SQL/JSON path into a chain of H2 dereference operators, which requires reading the concrete path text at translation time. If the path argument is a bind parameter or any non-literal expression, walker.getLiteralValue() fails and Hibernate throws this QueryException while rendering. Note: the message text says 'json_value' even though it comes from the json_exists emulation - the path is ultimately rendered through H2JsonValueFunction.renderJsonPath.","triggerScenarios":"HQL on H2 with a non-literal json_exists path: select json_exists(d.doc, :path) from Document d, or a path built by concatenation or a function call.","commonSituations":"Parameterized reporting queries where the JSON path arrives from the UI or configuration; H2 unit tests failing while the production database accepts parameterized paths.","solutions":["Inline the path as a literal: json_exists(d.doc, '$.flags[0]')","Keep the path literal and parameterize varying parts with PASSING: json_exists(d.doc, '$.flags[$i]' passing :idx as i)","Use a native H2 query for fully dynamic paths","Maintain a fixed set of literal-path queries instead of one parameterized query"],"exampleFix":"// before - throws on H2\nselect json_exists(d.doc, :path) from Document d\n\n// after - literal path with passing for the variable index\nselect json_exists(d.doc, '$.flags[$i]' passing :idx as i) from Document d","handlingStrategy":"validation","validationCode":"// Heuristic lint: json_exists paths must be string literals on H2\nprivate static final Pattern PARAM_EXISTS_PATH =\n    Pattern.compile(\"(?i)json_exists\\\\s*\\\\([^,]+,\\\\s*:\\\\w+\");\n\nstatic void assertLiteralJsonPaths(String hql) {\n    if (PARAM_EXISTS_PATH.matcher(hql).find()) {\n        throw new IllegalArgumentException(\n            \"json_exists 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, Boolean.class).getResultList();\n} catch (org.hibernate.QueryException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"only support literal json paths\")) {\n        // Note: the message says 'json_value' but this is the json_exists path check\n        throw new IllegalArgumentException(\"Inline the json_exists path as a literal: \" + hql, e);\n    }\n    throw e;\n}","preventionTips":["Never bind json_exists paths as query parameters on H2","Use the PASSING clause ('$.flags[$i]' passing :idx as i) for dynamic indexes","Store a fixed set of literal-path queries instead of one dynamic-path query"],"tags":["hibernate","h2","json","hql","json-exists","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"}