hibernate/hibernate-orm · error · HibernateException
cannot recreate collection while filter is enabled [%s : %s]
Error message
cannot recreate collection while filter is enabled [%s : %s]
What it means
BasicCollectionDecomposer is the graph-queue counterpart of CollectionUpdateAction for planning collection updates. When the collection needs full recreate and a filter affecting it is enabled (BasicCollectionDecomposer.java:318), it throws HibernateException("cannot recreate collection while filter is enabled [role : key]"). Bag-style collections (unindexed lists, arrays, maps without collection id) cannot be row-diffed, so Hibernate must delete-all and reinsert - unsafe under a filter because filtered rows are invisible and would be lost or wrongly inserted.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/action/queue/internal/decompose/collection/BasicCollectionDecomposer.java:318
// Do nothing - we only need to notify the cache
}
else {
final boolean affectedByFilters = persister.isAffectedByEnabledFilters( session );
final var eventMonitor = session.getEventMonitor();
final var event = eventMonitor.beginCollectionUpdateEvent();
boolean success = false;
try {
if ( !affectedByFilters && collection.empty() ) {
if ( !action.isEmptySnapshot() ) {
var removeOperation = planRemoveOperation( key, ordinalBase );
if ( removeOperation != null ) {
operations.add( removeOperation );
}
}
}
else if ( collection.needsRecreate( persister ) ) {
if ( affectedByFilters ) {
throw new HibernateException( String.format( Locale.ROOT,
"cannot recreate collection while filter is enabled [%s : %s]",
persister.getRole(),
key
) );
}
if ( !action.isEmptySnapshot() ) {
var removeOperation = planRemoveOperation( key, ordinalBase );
if ( removeOperation != null ) {
operations.add( removeOperation );
}
}
// Recreate INSERTs use INSERT_OFFSET which is higher than DELETE_OFFSET to avoid unique constraint violations
operations.addAll( planRecreateOperation(
collection,
key,
ordinalBase,
session
) );View on GitHub (pinned to fad1729dce)
Solutions
- Re-map the collection as diffable: @OrderColumn indexed list, Set, or @CollectionId (idbag) so needsRecreate() returns false
- Disable the filter before mutating: session.disableFilter("name"), flush, re-enable afterwards
- Mutate incrementally (add/remove specific elements) instead of clear()/replace when filters are active
- Move the @Filter off the collection role if it was never meant to apply there
Example fix
// before - clearing a bag while a filter is enabled @OneToMany(mappedBy = "user", cascade = ALL) private List<Role> roles = new ArrayList<>(); // bag: needs recreate user.getRoles().clear(); user.getRoles().addAll(newRoles); // flush -> "cannot recreate collection while filter is enabled" // after - indexed collection diffs rows, no recreate, no guard @OneToMany(mappedBy = "user", cascade = ALL) @OrderColumn(name = "sort_order") private List<Role> roles = new ArrayList<>();
Defensive patterns
Strategy: validation
Validate before calling
// guard bulk-replacement of a collection under active filters
public void replaceRoles(Session session, User user, List<Role> newRoles) {
if (session.getEnabledFilter("tenant") != null && needsRecreate(user.getRoles())) {
session.disableFilter("tenant");
try { user.setRoles(newRoles); session.flush(); }
finally { session.enableFilter("tenant").setParameter("tid", currentTenant()); }
} else {
user.setRoles(newRoles);
}
} Try / catch
try {
session.flush();
} catch (HibernateException e) {
if (e.getMessage() != null && e.getMessage().contains("cannot recreate collection")) {
// re-map the collection indexed/idbag, or retry with filters disabled
} else throw e;
} Prevention
- Prefer @OrderColumn/Set/@CollectionId mappings wherever filters apply to the owner
- Treat 'clear + addAll' on filtered bags as a forbidden pattern in code review
- Cover filter-enabled collection edits with integration tests
When it happens
Trigger: Running with the default graph flush queue (8.x), an enabled @Filter affecting the collection role, and a needsRecreate() collection (bag/array/no-id map) that was cleared or bulk-replaced during the session; flush plans the recreate and hits the guard with the role and key in the message.
Common situations: Soft-delete/tenant filters combined with @OneToMany List bags; replacing collection contents (clear + addAll) in services while a request-scoped filter is on; migrating from Set to List mappings under existing filters.
Related errors
- cannot recreate collection while filter is enabled: " + coll
- null key for collection: %s
- null key for collection: %s
- Decomposition not supported for %s
- Instance of '%s' references an unsaved transient instance of
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/42f083b331d2cc10.
Report an issue: GitHub.