hibernate/hibernate-orm · error · SemanticException

The 'from' clause of a subquery has a 'fetch' join

Error message

The 'from' clause of a subquery has a 'fetch' join

What it means

In getJoin, the join target is a subquery (JoinSubqueryContext - e.g. 'join lateral (select ...) s') and the join was marked 'fetch'. A derived join over a subquery result is not a managed association, so there is nothing to fetch; Hibernate throws SemanticException.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java:2355

		}
		else {
			throw new ParsingException( "unexpected join type" );
		}
	}

	@SuppressWarnings("unchecked")
	private <X> SqmJoin<X, ?> getJoin(
			SqmRoot<X> sqmRoot,
			SqmJoinType joinType,
			HqlParser.JoinTargetContext joinTargetContext,
			String alias,
			boolean fetch) {
		if ( joinTargetContext instanceof HqlParser.JoinPathContext joinPathContext ) {
			return (SqmJoin<X, ?>) joinPathContext.path().accept( this );
		}
		else if ( joinTargetContext instanceof HqlParser.JoinSubqueryContext joinSubqueryContext ) {
			if ( fetch ) {
				throw new SemanticException( "The 'from' clause of a subquery has a 'fetch' join", query );
			}
			if ( getCreationOptions().useStrictJpaCompliance() ) {
				throw new StrictJpaComplianceViolation(
						"The JPA specification does not support subqueries in the from clause. " +
								"Please disable the JPA query compliance if you want to use this feature.",
						StrictJpaComplianceViolation.Type.FROM_SUBQUERY
				);
			}

			final boolean lateral = joinSubqueryContext.LATERAL() != null;
			final var identifierConsumer = dotIdentifierConsumerStack.pop();
			final var subQuery = (SqmSubQuery<X>) joinSubqueryContext.subquery().accept( this );
			dotIdentifierConsumerStack.push( identifierConsumer );
			final var join = new SqmDerivedJoin<>( subQuery, alias, joinType, lateral, sqmRoot );
			processingStateStack.getCurrent().getPathRegistry().register( join );
			return join;
		}
		else if ( joinTargetContext instanceof HqlParser.JoinFunctionContext joinFunctionContext ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove the 'fetch' keyword from the subquery join: 'join lateral (select ...) s'
  2. Fetch only real, mapped associations of your roots

Example fix

// before
select e from Employee e join fetch lateral (select i from Item i where i.emp = e) s

// after
select e from Employee e join lateral (select i from Item i where i.emp = e) s
Defensive patterns

Strategy: validation

Validate before calling

// Reject 'join fetch lateral (select ...)' style constructs before execution
static boolean fetchOnSubqueryJoin(String hql) {
    return java.util.regex.Pattern.compile("join\\s+fetch\\s+(lateral\\s*)?\\(", java.util.regex.Pattern.CASE_INSENSITIVE).matcher(hql).find();
}
if (fetchOnSubqueryJoin(hql)) throw new IllegalArgumentException("'fetch' is not valid on joins targeting a subquery");

Try / catch

try {
    return em.createQuery(hql, Employee.class).getResultList();
} catch (org.hibernate.query.sqm.SemanticException e) {
    if (e.getMessage() != null && e.getMessage().contains("'fetch' join")) {
        throw new IllegalArgumentException("Remove 'fetch' from the (lateral) subquery join", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: 'select e from Employee e join fetch lateral (select ...) s on ...'; any 'join fetch' whose target is a (lateral) subquery in the from clause.

Common situations: Copy-pasting 'fetch' onto lateral joins adopted with Hibernate 6.6+; assuming fetch works uniformly on every join kind.

Related errors


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