hibernate/hibernate-orm · error · QueryException

H2 json_table() passing clause only supports literal json pa

Error message

H2 json_table() passing clause only supports literal json path passing values, but got {expression}

What it means

For json_table() on H2, the emulation inlines passing values directly into the rebuilt path text, so every passing expression must be a Literal. If the expression bound in the PASSING clause is a bind parameter or any computed expression, this QueryException reports the unsupported expression.

Source

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

				sb.append( " format json" );
			}
			sb.append( ')' );
		}
		for ( int i = 0; i < jsonPathElements.size(); i++ ) {
			final JsonPathHelper.JsonPathElement jsonPathElement = jsonPathElements.get( i );
			if ( jsonPathElement instanceof JsonPathHelper.JsonAttribute attribute ) {
				sb.append( "." );
				QuotingHelper.appendDoubleQuoteEscapedString( sb, attribute.attribute() );
			}
			else if ( jsonPathElement instanceof JsonPathHelper.JsonParameterIndexAccess parameterIndexAccess ) {
				assert passingClause != null;
				final String parameterName = parameterIndexAccess.parameterName();
				final Expression expression = passingClause.getPassingExpressions().get( parameterName );
				if ( expression == null ) {
					throw new QueryException( "JSON path [" + jsonPath + "] uses parameter [" + parameterName + "] that is not passed" );
				}
				if ( !( expression instanceof Literal literal) ) {
					throw new QueryException( "H2 json_table() passing clause only supports literal json path passing values, but got " + expression );
				}

				sb.append( '[' );
				sb.append( literal.getLiteralValue() );
				sb.append( "+1]" );
			}
			else {
				sb.append( '[' );
				sb.append( ( (JsonPathHelper.JsonIndexAccess) jsonPathElement ).index() + 1 );
				sb.append( ']' );
			}
		}
		return sb.toString();
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Replace the bind parameter with a literal value in the PASSING clause, for example PASSING 3 AS i.
  2. Build the HQL with the literal value interpolated so the passing expression stays a literal node.
  3. Switch this statement to a native query when the value must stay a bind parameter.
  4. Test such statements on a dialect with native json_table support.

Example fix

// before
Query q = session.createQuery(
  "select t.name from Entity e, json_table(e.doc, '$.rows[$i]' passing :n as i columns(name varchar)) t");
q.setParameter("n", 2);

// after
Query q = session.createQuery(
  "select t.name from Entity e, json_table(e.doc, '$.rows[$i]' passing 2 as i columns(name varchar)) t");
Defensive patterns

Strategy: validation

Validate before calling

// H2 json_table emulation: passing values must be literals.
boolean isH2 = session.getJdbcServices().getDialect() instanceof org.hibernate.dialect.H2Dialect;
if (isH2 && usesBindParameterInPassing) {
    throw new IllegalStateException("H2 json_table PASSING requires literal values; interpolate the value into HQL");
}
String hql = "select t.name from Entity e, json_table(e.doc, '$.rows[$i]' passing " + n + " as i columns(name varchar)) t";

Try / catch

try {
    return session.createQuery(hql).getResultList();
} catch (org.hibernate.QueryException e) {
    if (e.getMessage() != null && e.getMessage().contains("literal json path passing values")) {
        throw new UnsupportedOperationException("Interpolate a literal value into the H2 json_table PASSING clause", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A json_table() query on H2 passes a query parameter, for example PASSING :offset AS i. The instanceof Literal check fails because the expression is a junction or parameter node, and rendering aborts.

Common situations: Developers bind the index as a JDBC parameter to allow plan caching, which H2 emulation cannot inline. Queries written for Oracle or PostgreSQL json_table run unchanged on H2 test databases.

Related errors


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