hibernate/hibernate-orm · error · HibernateException

cannot recreate collection while filter is enabled: " + coll

Error message

cannot recreate collection while filter is enabled: " + collectionInfoString( persister, collection, key, session )

What it means

During flush, CollectionUpdateAction (CollectionUpdateAction.java:112) handles updates of owned collections. When a collection 'needs recreate' (true for bag-style collections such as unindexed Lists, arrays, and maps without a collection id, because Hibernate cannot diff rows and must delete-all + reinsert), and a @Filter is currently enabled that affects the collection, Hibernate throws HibernateException("cannot recreate collection while filter is enabled: ..."). The filter changes which rows are visible, so a delete-all/recreate would either drop filtered-out rows or insert rows the filter should hide - Hibernate refuses rather than corrupt data.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java:112

				// The collection should still be dirty.
				throw new AssertionFailure( "collection is not dirty" );
			}
			// Do nothing - we only need to notify the cache
		}
		else {
			final var eventMonitor = session.getEventMonitor();
			final var event = eventMonitor.beginCollectionUpdateEvent();
			boolean success = false;
			try {
				if ( !affectedByFilters && collection.empty() ) {
					if ( !emptySnapshot ) {
						persister.remove( key, session );
					}
					//TODO: else we really shouldn't have sent an update event to JFR
				}
				else if ( collection.needsRecreate( persister ) ) {
					if ( affectedByFilters ) {
						throw new HibernateException( "cannot recreate collection while filter is enabled: "
												+ collectionInfoString( persister, collection, key, session ) );
					}
					if ( !emptySnapshot ) {
						persister.remove( key, session );
					}
					persister.recreate( collection, key, session );
				}
				else {
					persister.deleteRows( collection, key, session );
					persister.updateRows( collection, key, session );
					persister.insertRows( collection, key, session );
				}
				success = true;
			}
			finally {
				eventMonitor.completeCollectionUpdateEvent( event, key, persister.getRole(), success, session );
			}
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Change the collection mapping so row diffs are possible: add @OrderColumn (indexed list), use a Set, or map with a collection id (@CollectionId / idbag) - then needsRecreate() is false and the guard is skipped
  2. Temporarily disable the filter before mutating the collection: session.disableFilter("name"), flush, then re-enable
  3. Avoid clearing/replacing filtered bag collections while filters are on; mutate incrementally (add/remove elements) instead of clear()+addAll()
  4. If the filter logically should not apply to that collection, move the @Filter definition so it does not affect the collection role

Example fix

// before - bag + enabled filter forces recreate and the exception
@OneToMany(mappedBy = "order", cascade = ALL)
private List<Item> items = new ArrayList<>();  // unindexed bag

// after - indexed collection can be diffed row-wise, no recreate needed
@OneToMany(mappedBy = "order", cascade = ALL)
@OrderColumn(name = "position")
private List<Item> items = new ArrayList<>();
Defensive patterns

Strategy: validation

Validate before calling

// before clearing/replacing a collection, make sure no filter affects it
public void replaceItems(Session session, Order order, List<Item> newItems) {
    Filter f = session.getEnabledFilter("softDelete");
    if (f != null) {
        throw new IllegalStateException(
            "disable filter 'softDelete' before replacing a bag collection, or map it as indexed/idbag");
    }
    order.getItems().clear();
    order.getItems().addAll(newItems);
}

Try / catch

try {
    session.flush();
} catch (HibernateException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("cannot recreate collection")) {
        // disable filters, re-map collection, or reject the operation with a domain error
    } else throw e;
}

Prevention

When it happens

Trigger: session.enableFilter(...) active on an entity whose collection is a bag (List without @OrderColumn), primitive array, or map without collection id; then clearing the collection or mutating it in a way that forces needsRecreate()==true; flush/commit triggers CollectionUpdateAction and the guard fires.

Common situations: Soft-delete or tenant filters (@Filter on entities) combined with @OneToMany List fields; multitenancy filters active for the whole request while business code clears/replaces a collection; upgrading mappings from Set to List and suddenly hitting recreate semantics.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/74d14443cc3be5cd. Report an issue: GitHub.