hibernate/hibernate-orm · error · IllegalArgumentException
Passed attribute name [%s] did not correspond to a collectio
Error message
Passed attribute name [%s] did not correspond to a collection (bag) reference [%s] relative to %s
What it means
AbstractSqmFrom.joinCollection(attributeName, joinType) resolves the attribute via getSubPathSource(attributeName) and requires it to be a BagPersistentAttribute (a Collection/bag mapping). If the attribute exists but is a Set, List, Map or singular attribute, Hibernate throws IllegalArgumentException showing the attribute name, the resolved path source and the navigable path.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/AbstractSqmFrom.java:539
return joinCollection( attributeName, JoinType.INNER );
}
@Nonnull
@Override
@SuppressWarnings("unchecked")
public <Y> SqmBagJoin<T, Y> joinCollection(@Nonnull String attributeName, @Nonnull JoinType jt) {
final var joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName );
if ( joinedPathSource instanceof BagPersistentAttribute ) {
final var join = buildBagJoin(
(BagPersistentAttribute<T, Y>) joinedPathSource,
SqmJoinType.from( jt ),
false
);
addSqmJoin( join );
return join;
}
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Passed attribute name [%s] did not correspond to a collection (bag) reference [%s] relative to %s",
attributeName,
joinedPathSource,
getNavigablePath()
)
);
}
@Nonnull
@Override
public <Y> SqmSetJoin<T, Y> joinSet(@Nonnull String attributeName) {
return joinSet( attributeName, JoinType.INNER );
}
@Nonnull
@OverrideView on GitHub (pinned to fad1729dce)
Solutions
- Use the join method matching the mapping: joinSet for Set, joinList for ordered List, joinMap for Map, join/join(entityType) for singular associations.
- Prefer the metamodel-typed overloads join(CollectionAttribute), join(SetAttribute), etc., which are compile-time safe.
- Check the attribute kind via the metamodel before choosing the join method in generic code.
Example fix
// before SqmBagJoin<Customer, Order> o = customerRoot.joinCollection( "orders", JoinType.LEFT ); // orders is a Set // after SqmSetJoin<Customer, Order> o = customerRoot.joinSet( "orders", JoinType.LEFT );
Defensive patterns
Strategy: type-guard
Type guard
static boolean isBag(ManagedType<?> type, String attr) {
return type.getAttribute( attr ) instanceof jakarta.persistence.metamodel.PluralAttribute<?, ?, ?> p
&& p.getCollectionType() == jakarta.persistence.metamodel.PluralAttribute.CollectionType.COLLECTION;
} Prevention
- Prefer metamodel-typed overloads join(CollectionAttribute)/join(SetAttribute)/... which cannot mismatch.
- In generic code, switch on PluralAttribute.getCollectionType() before picking joinCollection/joinSet/joinList/joinMap.
- After changing an entity field's container type, update every string-based join call for that attribute.
When it happens
Trigger: root.joinCollection("orders", JoinType.INNER) when orders is mapped as java.util.Set, java.util.List (with @OrderColumn) or java.util.Map; joinCollection on a @ManyToOne/@Basic attribute.
Common situations: Changing an entity field from List to Set between versions while the query code still calls joinCollection; generic query helpers that always use joinCollection for any plural attribute; a List field mapped without @OrderColumn is a bag in Hibernate and works, but a Set field does not.
Related errors
- Passed attribute name [%s] did not correspond to a collectio
- Passed attribute name [%s] did not correspond to a collectio
- Passed attribute [%s] did not correspond to a joinable refer
- Illegal empty CTE name
- Illegal CTE name [%s]. Names must start with an alphabetic c
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/5dace476b200e9c1.
Report an issue: GitHub.