hibernate/hibernate-orm · error · QueryException
H2 json_value only support literal json paths, but got " + a
Error message
H2 json_value only support literal json paths, but got " + arguments.jsonPath()
What it means
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.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/function/json/H2JsonExistsFunction.java:38
super( typeConfiguration, true, true );
}
@Override
protected void render(
SqlAppender sqlAppender,
JsonExistsArguments arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
// Json dereference errors by default if the JSON is invalid
if ( arguments.errorBehavior() != null && arguments.errorBehavior() != JsonExistsErrorBehavior.ERROR ) {
throw new QueryException( "Can't emulate on error clause on H2" );
}
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() );
}
arguments.jsonDocument().accept( walker );
sqlAppender.appendSql( " is not null and " );
H2JsonValueFunction.renderJsonPath(
sqlAppender,
arguments.jsonDocument(),
arguments.isJsonType(),
walker,
jsonPath,
arguments.passingClause()
);
sqlAppender.appendSql( " is not null" );
}
}
View on GitHub (pinned to fad1729dce)
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
Example fix
// before - throws on H2 select json_exists(d.doc, :path) from Document d // after - literal path with passing for the variable index select json_exists(d.doc, '$.flags[$i]' passing :idx as i) from Document d
Defensive patterns
Strategy: validation
Validate before calling
// Heuristic lint: json_exists paths must be string literals on H2
private static final Pattern PARAM_EXISTS_PATH =
Pattern.compile("(?i)json_exists\\s*\\([^,]+,\\s*:\\w+");
static void assertLiteralJsonPaths(String hql) {
if (PARAM_EXISTS_PATH.matcher(hql).find()) {
throw new IllegalArgumentException(
"json_exists 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, Boolean.class).getResultList();
} catch (org.hibernate.QueryException e) {
if (e.getMessage() != null && e.getMessage().contains("only support literal json paths")) {
// Note: the message says 'json_value' but this is the json_exists path check
throw new IllegalArgumentException("Inline the json_exists path as a literal: " + hql, e);
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Parameterized reporting queries where the JSON path arrives from the UI or configuration; H2 unit tests failing while the production database accepts parameterized paths.
Related errors
- H2 json_query only support literal json paths, but got " + j
- H2 json_table() only supports literal json paths, but got "
- H2 json_table() only supports literal json paths, but got {j
- CockroachDB json_value only support literal json paths, but
- JSON path [" + JsonPathHelper.toJsonPath( jsonPathElements )
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/07e541017c1c7a81.
Report an issue: GitHub.