hibernate/hibernate-orm · error · HibernateException
Found shared references to a collection: {}
Error message
Found shared references to a collection: {} What it means
During a single flush, Hibernate tracks every collection it has already reached (flushProcessingContext.markCollectionReached). Reaching the SAME collection instance a second time within one flush cycle means it is referenced from more than one place - typically two entities/properties pointing at one collection, or a circular reference between collections. The reached-check exists specifically to catch this user modeling error.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/engine/internal/Collections.java:185
final boolean isBytecodeEnhanced =
persister.getOwnerEntityPersister()
.getBytecodeEnhancementMetadata()
.isEnhancedForLazyLoading();
if ( isBytecodeEnhanced && !collection.wasInitialized() ) {
// the class of the collection owner is enhanced for lazy loading,
// and we found an un-initialized PersistentCollection, so skip it
if ( CORE_LOGGER.isTraceEnabled() ) {
CORE_LOGGER.skippingUninitializedBytecodeLazyCollection(
collectionInfoString( persister, collection, collectionEntry.getCurrentKey(), session ) );
}
flushProcessingContext.markCollectionReached( collection );
flushProcessingContext.markCollectionProcessed( collection );
}
// The reached status is just to detect any silly users
// who set up circular or shared references between/to collections.
else if ( flushProcessingContext.isCollectionReached( collection ) ) {
// We've been here before
throw new HibernateException( "Found shared references to a collection: " + type.getRole() );
}
else {
flushProcessingContext.markCollectionReached( collection );
logReachedCollection( collection, session, persister, collectionEntry );
prepareCollectionForUpdate( collection, collectionEntry, factory, flushProcessingContext );
}
}
private static void logReachedCollection(
PersistentCollection<?> collection,
SessionImplementor session,
CollectionPersister persister,
CollectionEntry collectionEntry) {
if ( CORE_LOGGER.isTraceEnabled() ) {
if ( collection.wasInitialized() ) {
CORE_LOGGER.collectionFoundInitialized(
collectionInfoString(
persister,View on GitHub (pinned to fad1729dce)
Solutions
- Give each association its own collection instance; to sync bidirectional sides use element operations: parent.getChildren().add(c); c.setParent(parent);
- Audit code that assigns a collection obtained from a getter (a.get...() returns Hibernate's PersistentCollection - never hand it to another owner).
- Clear caches/pools that hold Hibernate-managed collections across requests or entities.
- Simplify the model if collections genuinely must be shared - map it as one association with multiple parents (many-to-many).
Example fix
// before - second assignment shares the same collection instance invoiceA.setItems(invoiceB.getItems()); // after - copy elements into a fresh collection invoiceA.setItems(new ArrayList<>(invoiceB.getItems()));
Defensive patterns
Strategy: validation
Validate before calling
// Guard: before wiring two associations, ensure they do not share one instance
static void assertNoSharedInstance(Collection<?> a, Collection<?> b, String role) {
if (a != null && a == b) {
throw new IllegalArgumentException("Shared collection instance for " + role
+ " - copy elements into separate collections");
}
} Type guard
static boolean isPersistentCollection(Object c) {
return c instanceof org.hibernate.collection.spi.PersistentCollection;
} Try / catch
catch (HibernateException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Found shared references to a collection")) {
// same collection reached twice in one flush; locate the duplicate reference and copy
throw new MappingMisuseException(e.getMessage(), e);
}
throw e;
} Prevention
- Synchronize bidirectional relations with element add/remove, never by assigning collection references.
- Never store a collection obtained from an entity getter inside another entity.
- Audit caches/pools that may hand the same collection object to multiple entities.
When it happens
Trigger: Two associations (two entities, or two collection-valued properties) referencing the same collection instance within the objects reachable at flush; bidirectional collection wiring that assigns one side's collection object to the other side; shared collections in cached or pooled domain objects. Thrown from processReachableCollection on the second visit.
Common situations: Synchronizing both sides of a bidirectional relation by copying the collection reference instead of adding elements; DTO round-trips that put one collection into two parents; session cache/second-level cache returning a shared collection; utility code that 'reuses' collections for memory reasons.
Related errors
- Found two representations of same collection: {}
- A collection with orphan deletion was no longer referenced b
- Collection with orphan orphan delete enabled has modifier ow
- cannot recreate collection while filter is enabled: " + coll
- cannot recreate collection while filter is enabled [%s : %s]
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/094183c84e66a6a8.
Report an issue: GitHub.