{"record":{"id":"068ab68094d39a1a","repo":"hibernate/hibernate-orm","slug":"h2-json-value-only-support-literal-json-paths-but-068ab6","errorCode":null,"errorMessage":"H2 json_value only support literal json paths, but got {jsonPath}","messagePattern":"H2 json_value only support literal json paths, but got (.+?)","errorType":"exception","errorClass":"QueryException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonValueFunction.java","lineNumber":73,"sourceCode":"\t\t}\n\t\tfinal boolean hexDecoding;\n\t\tif ( arguments.returningType() != null ) {\n\t\t\thexDecoding = H2JsonValueFunction.needsHexDecoding( arguments.returningType().getJdbcMapping() );\n\t\t\tsqlAppender.appendSql( \"cast(\" );\n\t\t\tif ( hexDecoding ) {\n\t\t\t\t// We encode binary data as hex, so we have to decode here\n\t\t\t\tsqlAppender.appendSql( \"hextoraw(regexp_replace(\" );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\thexDecoding = false;\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\n\t\tsqlAppender.appendSql( \"stringdecode(regexp_replace(nullif(\" );\n\t\trenderJsonPath(\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( \",JSON'null'),'^\\\"(.*)\\\"$','$1'))\");\n\n\t\tif ( arguments.returningType() != null ) {\n\t\t\tif ( hexDecoding ) {\n\t\t\t\tsqlAppender.appendSql( \",'([0-9a-f][0-9a-f])','00$1'))\" );\n\t\t\t}\n\t\t\tsqlAppender.appendSql( \" as \" );","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonValueFunction.java#L55-L91","documentation":"Hibernate emulates json_value() on H2 by building a regexp_replace() expression at SQL generation time. To do this, it must read the JSON path as a string literal through SqlAstTranslator.getLiteralValue(). When the path argument is a bind parameter or any non-literal expression, getLiteralValue throws, and this QueryException reports it. The error occurs during query translation, before SQL runs against H2.","triggerScenarios":"An HQL or Criteria query calls json_value(doc, :path) or json_value(doc, someExpression) while the H2Dialect is active. The path is not a quoted string literal, so walker.getLiteralValue(arguments.jsonPath()) fails and the catch block throws.","commonSituations":"Developers write a query once for PostgreSQL or Oracle (native json_value accepts parameters) and run integration tests on H2. Or they try to keep the path configurable through a query parameter. H2 test containers and in-memory H2 databases expose the limitation.","solutions":["Inline the JSON path as a string literal: json_value(e.doc, '$.name') instead of json_value(e.doc, :path).","Build the HQL string in Java by concatenating the path constant, so each generated query still contains a literal path.","If the path must be dynamic per execution, fall back to a native query for this statement.","Run the test against a dialect with native JSON support (PostgreSQL, Oracle, SQL Server) when the query uses dynamic paths."],"exampleFix":"// before\nList results = session.createQuery(\"select json_value(e.doc, :p) from Entity e\", String.class)\n        .setParameter(\"p\", \"$.customer.name\")\n        .getResultList();\n\n// after\nList results = session.createQuery(\"select json_value(e.doc, '$.customer.name') from Entity e\", String.class)\n        .getResultList();","handlingStrategy":"validation","validationCode":"// Before creating the query: only H2 needs a literal path.\nboolean isH2 = session.getJdbcServices().getDialect() instanceof org.hibernate.dialect.H2Dialect;\nString path = \"$\" + \".customer.name\";\nif (isH2 && pathIsParameter) {\n    throw new IllegalStateException(\"H2 json_value requires a literal JSON path: \" + path);\n}\n// Build HQL with the path inlined as a literal.\nString hql = \"select json_value(e.doc, '\" + path + \"') from Entity e\";","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql, String.class).getResultList();\n} catch (org.hibernate.QueryException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"literal json paths\")) {\n        throw new UnsupportedOperationException(\"Inline the JSON path as a literal for H2\", e);\n    }\n    throw e;\n}","preventionTips":["Keep a project rule: JSON path arguments are string literals, never query parameters.","Store path constants next to the query strings that use them.","Run JSON query integration tests on the production dialect, not only on H2."],"tags":["hibernate","h2","json","json-value","literal-required","query-exception"],"backgroundTag":"json-path-literal-required","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}