hibernate/hibernate-orm · error · SemanticException
The 'from' clause of a subquery has a 'fetch'
Error message
The 'from' clause of a subquery has a 'fetch'
What it means
consumeJoin throws when the 'fetch' keyword appears on a join inside a subquery (processingStateStack.depth() > 1). Fetching is only defined for the outermost query: a subquery produces intermediate results, not managed results whose associations could be initialized, so 'fetch' in a nested from clause is a semantic error.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java:2287
}
private JpaMetamodel getJpaMetamodel() {
return getCreationContext().getJpaMetamodel();
}
@Override
public final SqmJoin<?, ?> visitJoin(HqlParser.JoinContext parserJoin) {
throw new UnsupportedOperationException( "Unexpected call to #visitJoin, see #consumeJoin" );
}
protected <X> void consumeJoin(HqlParser.JoinContext parserJoin, SqmRoot<X> sqmRoot) {
final var joinType = getSqmJoinType( parserJoin.joinType() );
final var qualifiedJoinTargetContext = parserJoin.joinTarget();
final String alias = extractAlias( getVariable( qualifiedJoinTargetContext ) );
final boolean fetch = parserJoin.FETCH() != null;
if ( fetch && processingStateStack.depth() > 1 ) {
throw new SemanticException( "The 'from' clause of a subquery has a 'fetch'", query );
}
final var joinRestrictionContext = parserJoin.joinRestriction();
// Joins are allowed to be reused if they don't have a join condition
final var allowReuse = joinRestrictionContext == null;
dotIdentifierConsumerStack.push( new QualifiedJoinPathConsumer( sqmRoot, joinType, fetch, alias, allowReuse, this ) );
try {
final var join = getJoin( sqmRoot, joinType, qualifiedJoinTargetContext, alias, fetch );
if ( join instanceof SqmEntityJoin<?,?> || join instanceof SqmDerivedJoin<?> || join instanceof SqmCteJoin<?> ) {
sqmRoot.addSqmJoin( join );
}
else if ( join instanceof SqmAttributeJoin<?, ?> attributeJoin ) {
if ( getCreationOptions().useStrictJpaCompliance() ) {
if ( join.getExplicitAlias() != null && attributeJoin.isFetched() ) {
throw new StrictJpaComplianceViolation(
"Encountered aliased fetch join, but strict JPQL compliance was requested",
StrictJpaComplianceViolation.Type.ALIASED_FETCH_JOIN
);View on GitHub (pinned to fad1729dce)
Solutions
- Remove 'fetch' from the join inside the subquery
- Move the fetch join to the outer query: 'select e from Employee e left join fetch e.items'
- Use a plain join in the subquery - fetching inside it has no effect anyway
Example fix
// before select e from Employee e where exists (select 1 from e.items i join fetch i.subTasks st) // after select e from Employee e left join fetch e.items i where exists (select 1 from Employee e2 where e2.id = e.id and size(e2.items) > 0)
Defensive patterns
Strategy: validation
Validate before calling
// Lint generated HQL: 'fetch' must not appear inside a subquery's from clause
static boolean fetchInsideSubquery(String hql) {
java.util.regex.Matcher m = java.util.regex.Pattern.compile("\\((?:select\\s+).*?\\)", java.util.regex.Pattern.CASE_INSENSITIVE | java.util.regex.Pattern.DOTALL).matcher(hql);
while (m.find()) {
if (m.group().toLowerCase().contains(" join fetch ")) return true;
}
return false;
} Try / catch
try {
return em.createQuery(hql, Employee.class).getResultList();
} catch (org.hibernate.query.sqm.SemanticException e) {
if (e.getMessage() != null && e.getMessage().contains("subquery has a 'fetch'")) {
throw new IllegalArgumentException("Remove 'fetch' from joins inside subqueries; fetch in the outer query instead", e);
}
throw e;
} Prevention
- Reserve 'join fetch' for the outermost query only
- When refactoring an exists/in predicate out of a main query, strip fetch keywords from the moved joins
- Fetching inside a subquery has no effect anyway - plain joins are always correct there
When it happens
Trigger: 'select e from Employee e where exists (select 1 from e.items i join fetch i.subTasks st)'; any join marked 'fetch' inside a subquery from clause.
Common situations: Copying an outer fetch join into a subquery while refactoring an exists/in predicate; ORMs/query DSLs that append 'fetch' to every join uniformly.
Related errors
- The 'from' clause of a subquery has a 'fetch' join
- Implicitly-polymorphic domain path in subquery '${name}'
- Could not resolve entity or correlation path '${name}'
- FROM_SUBQUERY
- ALIASED_FETCH_JOIN
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/ab82fa4c7330e29e.
Report an issue: GitHub.