hibernate/hibernate-orm · error · MappingException
many-to-many defining filter or where without join fetching
Error message
many-to-many defining filter or where without join fetching is not valid within collection [%s] using join fetching
What it means
For a many-to-many collection element that declares <filter> elements or a where= restriction, Hibernate must apply that constraint inside the same SQL as the collection load. When the collection binding's fetch style is JOIN but the element (many-to-one) binding resolved to a non-JOIN fetch (typically fetch='select' on the <many-to-many>), the constraint cannot be applied and binding fails.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java:3215
getNonEmptyOrConjunctionIfBothNonEmpty(
referencedEntityBinding.getWhere(),
elementSource.getWhere()
)
);
collectionBinding.setManyToManyOrdering( elementSource.getOrder() );
bindManyToManyFilters( elementSource, mappingDocument, collectionBinding, elementBinding );
}
private void bindManyToManyFilters(
PluralAttributeElementSourceManyToMany elementSource,
MappingDocument mappingDocument,
Collection collectionBinding,
ManyToOne elementBinding) {
if ( !isEmpty( elementSource.getFilterSources() )
|| elementSource.getWhere() != null ) {
if ( collectionBinding.getFetchStyle() == FetchStyle.JOIN
&& elementBinding.getFetchStyle() != FetchStyle.JOIN ) {
throw new MappingException(
"many-to-many defining filter or where without join fetching is not "
+ "valid within collection [%s] using join fetching"
.formatted( getPluralAttributeSource().getAttributeRole().getFullPath() ),
mappingDocument.getOrigin()
);
}
}
for ( var filterSource : elementSource.getFilterSources() ) {
bindManyToManyFilter( mappingDocument, collectionBinding, filterSource );
}
}
private void bindManyToManyFilter(
MappingDocument mappingDocument, Collection collectionBinding, FilterSource filterSource) {
final String name = filterSource.getName();
if ( name == null ) {
if ( BOOT_LOGGER.isTraceEnabled() ) {View on GitHub (pinned to fad1729dce)
Solutions
- Remove fetch='select' from the <many-to-many> element so it follows the collection's join fetching
- Or switch the collection itself to fetch='select' (or default) so the filter/where can be applied in a separate select
- Or drop the where/filters on the element if join fetching the collection matters more
Example fix
// before
<set name='roles' fetch='join'>
<key column='user_id'/>
<many-to-many class='Role' fetch='select' where="deleted = false"/>
</set>
// after
<set name='roles' fetch='join'>
<key column='user_id'/>
<many-to-many class='Role' where="deleted = false"/>
</set> Defensive patterns
Strategy: validation
Validate before calling
NodeList m2ms = doc.getElementsByTagName("many-to-many");
for (int i = 0; i < m2ms.getLength(); i++) {
Element m = (Element) m2ms.item(i);
boolean hasFilterOrWhere = m.getElementsByTagName("filter").getLength() > 0 || m.getAttributeNode("where") != null;
Element collection = (Element) m.getParentNode();
boolean collectionJoin = "join".equals(collection.getAttribute("fetch"));
boolean elementSelect = "select".equals(m.getAttribute("fetch"));
if (hasFilterOrWhere && collectionJoin && elementSelect) {
throw new IllegalStateException("filtered many-to-many inside join-fetched collection must not use fetch='select'");
}
} Try / catch
catch (MappingException e) at bootstrap; the message names the collection. Remove fetch='select' from the many-to-many or switch the collection off join fetching so the filter/where can be applied.
Prevention
- Do not override the element fetch to select inside join-fetched collections that use filters/where
- Decide fetch strategy at the collection level when row filters are involved
- Test filtered collections against real SQL during development
When it happens
Trigger: <bag name='...' fetch='join'><many-to-many class='...' fetch='select' where='...'/></bag>, or a <many-to-many> containing <filter> elements while the collection is join-fetched and the element fetch was overridden to select.
Common situations: Tuning fetch strategies per association and overriding the element's fetch to select; adding row-level filters/where clauses to existing join-fetched collections; copying filter definitions from select-fetched sets into join-fetched bags.
Related errors
- No filter condition found for filter [%s] associated with ma
- Error transforming many-to-many :
- Property '${property}' uses *-to-many mapping with mappedBy
- Fetch profile '{}' has a '@FetchOverride' with 'fetch=LAZY'
- Collection '{}' annotated '@NotFound' is not a '@ManyToMany'
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/ceb79c97b71a9715.
Report an issue: GitHub.