hibernate/hibernate-orm · error · QueryException

H2 json_query only support literal json paths, but got " + j

Error message

H2 json_query only support literal json paths, but got " + jsonPathExpression

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonQueryFunction.java:67

				walker
		);
	}

	static void appendJsonQuery(
			SqlAppender sqlAppender,
			Expression jsonDocument,
			boolean isJsonType,
			Expression jsonPathExpression,
			@Nullable JsonPathPassingClause passingClause,
			@Nullable JsonQueryWrapMode wrapMode,
			@Nullable JsonQueryEmptyBehavior emptyBehavior,
			SqlAstTranslator<?> walker) {
		final String jsonPath;
		try {
			jsonPath = walker.getLiteralValue( jsonPathExpression );
		}
		catch (Exception ex) {
			throw new QueryException( "H2 json_query only support literal json paths, but got " + jsonPathExpression );
		}
		appendJsonQuery( sqlAppender, jsonDocument, isJsonType, jsonPath, passingClause, wrapMode, emptyBehavior, walker );
	}

	static void appendJsonQuery(
			SqlAppender sqlAppender,
			Expression jsonDocument,
			boolean isJsonType,
			String jsonPath,
			@Nullable JsonPathPassingClause passingClause,
			@Nullable JsonQueryWrapMode wrapMode,
			@Nullable JsonQueryEmptyBehavior emptyBehavior,
			SqlAstTranslator<?> walker) {
		if ( emptyBehavior == JsonQueryEmptyBehavior.EMPTY_ARRAY || emptyBehavior == JsonQueryEmptyBehavior.EMPTY_OBJECT ) {
			sqlAppender.appendSql( "coalesce(" );
		}

		if ( wrapMode == JsonQueryWrapMode.WITH_WRAPPER ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Inline the path as a literal: json_query(d.doc, '$.items[*]')
  2. Parameterize parts inside a literal path with PASSING: json_query(d.doc, '$.items[$i]' passing :idx as i)
  3. Fall back to a native H2 query for fully dynamic paths
  4. Keep a whitelist of pre-validated literal-path queries

Example fix

// before - throws on H2
select json_query(d.doc, :path) from Document d

// after - literal path with passing for the variable index
select json_query(d.doc, '$.items[$i]' passing :idx as i) from Document d
Defensive patterns

Strategy: validation

Validate before calling

// Heuristic lint: json_query paths must be string literals on H2
private static final Pattern PARAM_QUERY_PATH =
    Pattern.compile("(?i)json_query\\s*\\([^,]+,\\s*:\\w+");

static void assertLiteralJsonPaths(String hql) {
    if (PARAM_QUERY_PATH.matcher(hql).find()) {
        throw new IllegalArgumentException(
            "json_query path must be a string literal on H2; use PASSING for variable parts");
    }
}

Type guard

// Java predicate (type-guard analogue) for Criteria/SQM path expressions
static boolean isLiteralPath(org.hibernate.query.sqm.tree.expression.SqmExpression<?> pathExpr) {
    return pathExpr instanceof org.hibernate.query.sqm.tree.expression.SqmLiteral<?>;
}

Try / catch

try {
    return session.createQuery(hql, String.class).getResultList();
} catch (org.hibernate.QueryException e) {
    if (e.getMessage() != null && e.getMessage().contains("only support literal json paths")) {
        throw new IllegalArgumentException("Inline the json_query path as a literal: " + hql, e);
    }
    throw e;
}

Prevention

When it happens

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

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

Related errors


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