hibernate/hibernate-orm · error · IllegalStateException
Requested join fetch with association [%s] with '%s' join ty
Error message
Requested join fetch with association [%s] with '%s' join type, but found existing join fetch with '%s' join type.
What it means
Thrown as IllegalStateException by SqmUtil.findCompatibleFetchJoin when the same association is already join-fetched but with a different SqmJoinType than the one now requested. When resolving a fetch of a path, Hibernate reuses an existing fetched attribute join only if the join type matches; a mismatch is treated as a user error because two fetches of one association with different join types have contradictory semantics (an inner fetch cannot coexist with a left fetch of the same relation).
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java:454
}
else {
expression.accept( pathVisitor );
}
}
return navigablePaths;
}
public static <T, A> SqmAttributeJoin<T, A> findCompatibleFetchJoin(
SqmFrom<?, T> sqmFrom,
SqmPathSource<A> pathSource,
SqmJoinType requestedJoinType) {
for ( final var join : sqmFrom.getSqmJoins() ) {
if ( join.getModel() == pathSource ) {
final var attributeJoin = (SqmAttributeJoin<T, ?>) join;
if ( attributeJoin.isFetched() ) {
final var joinType = join.getSqmJoinType();
if ( joinType != requestedJoinType ) {
throw new IllegalStateException( String.format(
"Requested join fetch with association [%s] with '%s' join type, " +
"but found existing join fetch with '%s' join type.",
pathSource.getPathName(),
requestedJoinType,
joinType
) );
}
//noinspection unchecked
return (SqmAttributeJoin<T, A>) attributeJoin;
}
}
}
return null;
}
public static Map<QueryParameterImplementor<?>, Map<SqmParameter<?>, List<JdbcParametersList>>> generateJdbcParamsXref(
DomainParameterXref domainParameterXref,
JdbcParameterBySqmParameterAccess jdbcParameterBySqmParameterAccess) {View on GitHub (pinned to fad1729dce)
Solutions
- Make the join types identical for every fetch of the same association (use 'left join fetch' both times, or 'join fetch' both times)
- Remove the duplicate fetch — a single fetch of the association already loads it
- In Criteria, reuse the existing Fetch object instead of calling fetch(attribute, joinType) again for the same attribute
- Audit @EntityGraph / applied graphs for a conflicting fetch of the same association and align its join type
Example fix
// before String hql = "select p from Person p join fetch p.address left join fetch p.address"; // after String hql = "select p from Person p left join fetch p.address";
Defensive patterns
Strategy: validation
Validate before calling
static void assertNoConflictingFetchJoins(FetchParent<?, ?> parent) {
Map<String, JoinType> seen = new HashMap<>();
for (Fetch<?, ?> f : parent.getFetches()) {
JoinType prev = seen.put(f.getAttribute().getName(), f.getJoinType());
if (prev != null && prev != f.getJoinType()) {
throw new IllegalStateException(
"Conflicting join fetch types for " + f.getAttribute().getName());
}
}
} Try / catch
try {
return session.createQuery(hql, Person.class).getResultList();
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("existing join fetch")) {
// two fetches of one association with different join types: fix the query string
throw new IllegalArgumentException("Conflicting fetch join types in query: " + hql, e);
}
throw e;
} Prevention
- Search query strings for repeated 'join fetch <same path>' with different join types
- Centralize the fetch strategy (and its join type) per association in one place
- Reuse the existing Fetch object in criteria instead of fetching the same attribute twice
When it happens
Trigger: HQL that fetches the same association twice with different join types: 'select p from Person p left join fetch p.address join fetch p.address'; Criteria code calling root.fetch("address", JoinType.LEFT) and later root.fetch("address", JoinType.INNER); query builders or @EntityGraph handling that add a default inner 'join fetch' on top of an existing 'left join fetch' of the same path.
Common situations: One team fixes an N+1 with 'join fetch' while another layer (entity graph, repository fragment, generated query) already declared 'left join fetch' on the same association; upgrades that change default fetch join generation; criteria utilities that always apply fetches with INNER unless told otherwise.
Related errors
- Could not determine ValueMapping for SqmExpression: {}
- Domain result for non-scalar subquery shouldn't be created
- Insert conflict 'do update' clause with constraint name is n
- field type not supported on Derby: " + unit
- format() function not supported on Derby
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/0b8512f1911de160.
Report an issue: GitHub.