hibernate/hibernate-orm · error · HibernateException

Immutable collection dereferenced by owner: {}

Error message

Immutable collection dereferenced by owner: {}

What it means

checkOnChangedOwner validates collections whose entry is read-only (loaded as immutable - read-only session/entity or immutable mapping). If such a collection is dereferenced (the owner's property now points at a different collection or null) while the owner is still alive (not deleted/gone), Hibernate throws: an immutable collection cannot be replaced, because the loaded state is the database truth and no snapshot/update path exists for it.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/internal/Collections.java:302

			else if ( collection.isDirty() ) {
				// the collection's elements have changed
				flushProcessingContext.queueCollectionUpdate(
						collection,
						loadedPersister,
						collectionEntry.getLoadedKey(),
						collectionEntry.isSnapshotEmpty( collection )
				);
			}
		}
	}

	private static void checkOnChangedOwner(PersistentCollection<?> collection, CollectionEntry collectionEntry, CollectionPersister loadedPersister, CollectionPersister currentPersister) {
		final boolean immutableDereferenced =
				collectionEntry.isReadOnly()
				&& loadedPersister != null
				&& !isOwnerDeletedOrGone( collection );
		if ( immutableDereferenced ) {
			throw new HibernateException( "Immutable collection dereferenced by owner: "
						+ collectionInfoString( loadedPersister.getRole(), collectionEntry.getLoadedKey() ) );
		}


		final boolean orphanDeleteAndRoleChanged =
				loadedPersister != null
				&& currentPersister != null
				&& loadedPersister.hasOrphanDelete();
		if ( orphanDeleteAndRoleChanged ) {
			throw new HibernateException(
					"Collection with orphan orphan delete enabled has modifier owner: "
					+ collectionInfoString( loadedPersister.getRole(), collectionEntry.getLoadedKey() ) );
		}
	}

	private static boolean isOwnerDeletedOrGone(PersistentCollection<?> collection) {
		final Object owner = collection.getOwner();
		assert owner != null;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Load the entity in read-write mode before modifying it: session.setDefaultReadOnly(false) / avoid readOnly() on the load.
  2. Make the collection mapping mutable (remove immutable=true / ensure the owner is not loaded read-only).
  3. Do not replace the collection on read-only entities - delete and reinsert the owner if the data must change.
  4. Check collectionInfoString in the message to identify which role/owner triggered it and fix that code path.

Example fix

// before - entity loaded read-only, collection replaced
Session ro = sf.withOptions().readOnly(true).openSession();
Order o = ro.find(Order.class, id);
o.setLines(new ArrayList<>());      // dereference -> HibernateException at flush
// after - load read-write for modification
Session rw = sf.openSession();
Order o = rw.find(Order.class, id);
o.getLines().clear();
Defensive patterns

Strategy: validation

Validate before calling

// Guard: verify the entity is writable before letting code replace its collections
boolean writable = session.getEntityPersister(null, entity).isMutable()
        && !session.isReadOnly(entity);
if (!writable) throw new IllegalStateException(
    "Entity loaded read-only; collection replacement not allowed - reload read-write first");

Try / catch

catch (HibernateException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Immutable collection dereferenced by owner")) {
        // reload the owner in a read-write session before editing
        throw new MappingMisuseException(e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling a setter that replaces a collection on an entity loaded read-only (session.setDefaultReadOnly(true), sharedSessionBuilder .readOnly(true), @Immutable-adjacent read-only entries), or a collection mapped immutable, then dereferencing it (set X(null) or setX(newCollection)) and flushing while the owner is managed.

Common situations: Read-only report sessions upgraded to write sessions; entities loaded with LockOptions.READ_ONLY then modified; mapping collections to immutable where the UI still lets users replace lists; load-then-modify flows on top of 'optimization' read-only flags.

Related errors


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