hibernate/hibernate-orm · error · QueryException

H2 json_value only support literal json paths, but got {json

Error message

H2 json_value only support literal json paths, but got {jsonPath}

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonValueFunction.java:73

		}
		final boolean hexDecoding;
		if ( arguments.returningType() != null ) {
			hexDecoding = H2JsonValueFunction.needsHexDecoding( arguments.returningType().getJdbcMapping() );
			sqlAppender.appendSql( "cast(" );
			if ( hexDecoding ) {
				// We encode binary data as hex, so we have to decode here
				sqlAppender.appendSql( "hextoraw(regexp_replace(" );
			}
		}
		else {
			hexDecoding = false;
		}
		final String jsonPath;
		try {
			jsonPath = walker.getLiteralValue( arguments.jsonPath() );
		}
		catch (Exception ex) {
			throw new QueryException( "H2 json_value only support literal json paths, but got " + arguments.jsonPath() );
		}

		sqlAppender.appendSql( "stringdecode(regexp_replace(nullif(" );
		renderJsonPath(
				sqlAppender,
				arguments.jsonDocument(),
				arguments.isJsonType(),
				walker,
				jsonPath,
				arguments.passingClause()
		);
		sqlAppender.appendSql( ",JSON'null'),'^\"(.*)\"$','$1'))");

		if ( arguments.returningType() != null ) {
			if ( hexDecoding ) {
				sqlAppender.appendSql( ",'([0-9a-f][0-9a-f])','00$1'))" );
			}
			sqlAppender.appendSql( " as " );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Inline the JSON path as a string literal: json_value(e.doc, '$.name') instead of json_value(e.doc, :path).
  2. Build the HQL string in Java by concatenating the path constant, so each generated query still contains a literal path.
  3. If the path must be dynamic per execution, fall back to a native query for this statement.
  4. Run the test against a dialect with native JSON support (PostgreSQL, Oracle, SQL Server) when the query uses dynamic paths.

Example fix

// before
List results = session.createQuery("select json_value(e.doc, :p) from Entity e", String.class)
        .setParameter("p", "$.customer.name")
        .getResultList();

// after
List results = session.createQuery("select json_value(e.doc, '$.customer.name') from Entity e", String.class)
        .getResultList();
Defensive patterns

Strategy: validation

Validate before calling

// Before creating the query: only H2 needs a literal path.
boolean isH2 = session.getJdbcServices().getDialect() instanceof org.hibernate.dialect.H2Dialect;
String path = "$" + ".customer.name";
if (isH2 && pathIsParameter) {
    throw new IllegalStateException("H2 json_value requires a literal JSON path: " + path);
}
// Build HQL with the path inlined as a literal.
String hql = "select json_value(e.doc, '" + path + "') from Entity e";

Try / catch

try {
    return session.createQuery(hql, String.class).getResultList();
} catch (org.hibernate.QueryException e) {
    if (e.getMessage() != null && e.getMessage().contains("literal json paths")) {
        throw new UnsupportedOperationException("Inline the JSON path as a literal for H2", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/068ab68094d39a1a. Report an issue: GitHub.