Regression 6.6 → 7.x: merge() of a managed parent with a cleared orphanRemoval collection throws DetachedObjectException

On Hibernate ORM 7.2.19.Final, calling merge() on an already-managed parent whose orphanRemoval = true collection has been emptied throws org.hibernate.DetachedObjectException: Given entity is not associated with the persistence context during flush. The same code runs without error on 6.6.53.Final (the orphan is deleted normally). Using persist() instead of merge() in the exact same scenario also works.

This looks like a regression. Minimal, self-contained reproduction below (pure Hibernate, no Spring).

Entities

@Entity
public class DetachParent {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<DetachChild> children = new ArrayList<>();

    public Long getId() {
        return id;
    }

    public List<DetachChild> getChildren() {
        return children;
    }
}


@Entity
public class DetachChild {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne
    private DetachParent parent;

    public Long getId() { return id; }
    public DetachParent getParent() { return parent; }
    public void setParent(DetachParent invoice) { this.parent = invoice; }
}

    public void setParent(DetachParent parent) { this.parent = parent; }
}

Test

public class DetachTest {

    /**
     * Creates a parent with a child in a transaction
     * When the transaction closes, the session is not discarded due to open-session-in-view
     * Clear the child in a different transaction
     */
    @Test
    void mergeOfManagedParentWithClearedOrphanCollection() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu");
        try (emf) {
            EntityManager entityManager = emf.createEntityManager();
            DetachParent parent = createParentWithChildInTx(entityManager);
            parent.getChildren().clear();

            entityManager.getTransaction().begin();
            System.out.println("[tx2] em.contains(parent) BEFORE merge = " + entityManager.contains(parent));
            // Spring JPA saveAndFlush does merge+flush
            entityManager.merge(parent);
            entityManager.flush();
            entityManager.getTransaction().commit();
            entityManager.close();
        }
    }

    /**
     * Creates a parent with a child in a transaction
     * When the transaction closes, the session is not discarded due to open-session-in-view
     * Clear the child and a new child in a different transaction
     */
    @Test
    void mergeOfManagedParentWithClearedOrphanCollectionAndNewEntry() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu");
        try (emf) {
            EntityManager entityManager = emf.createEntityManager();
            DetachParent parent = createParentWithChildInTx(entityManager);
            parent.getChildren().clear();

            // Adding a new child does not cause the DetachException
            DetachChild child = new DetachChild();
            child.setParent(parent);
            parent.getChildren().add(child);

            entityManager.getTransaction().begin();
            System.out.println("[tx2] em.contains(parent) BEFORE merge = " + entityManager.contains(parent));
            // Spring JPA saveAndFlush does merge+flush
            entityManager.merge(parent);
            entityManager.flush();
            entityManager.getTransaction().commit();
            entityManager.close();
        }
    }

    DetachParent createParentWithChildInTx(EntityManager entityManager) {
        entityManager.getTransaction().begin();
        DetachParent parent = new DetachParent();
        DetachChild child = new DetachChild();
        child.setParent(parent);
        parent.getChildren().add(child);
        entityManager.persist(parent);
        entityManager.flush();
        entityManager.getTransaction().commit();
        return parent;
    }
}

Expected vs actual

  • Expected: orphan removal deletes the child — as it does under persist() in the same scenario, and as merge() does on 6.5.2.
  • Actual (7.2.19): the orphan child is routed through the detached-delete path and throws:
Caused by: org.hibernate.DetachedObjectException: Given entity is not associated with the persistence context
        at org.hibernate.event.internal.DefaultDeleteEventListener.deleteDetachedEntity(DefaultDeleteEventListener.java:170)
        at org.hibernate.event.internal.DefaultDeleteEventListener.deleteUnmanagedInstance(DefaultDeleteEventListener.java:163)
        at org.hibernate.event.internal.DefaultDeleteEventListener.delete(DefaultDeleteEventListener.java:148)
        at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:84)
        at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:149)
        at org.hibernate.internal.SessionImpl.fireDelete(SessionImpl.java:911)

A multimodule that contains both hibernate 6 and 7. Run mvn clean test to reproduce the problem:

/IdeaProjects/robaws/hibernateOrphanRemoval$ mvn clean test
WARNING: A restricted method in java.lang.System has been called
WARNING: java.lang.System::load has been called by org.fusesource.jansi.internal.JansiLoader in an unnamed module (file:/home/devlooj/.sdkman/candidates/maven/current/lib/jansi-2.4.0.jar)
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
WARNING: Restricted methods will be blocked in a future release unless native access is enabled

WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::objectFieldOffset has been called by com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper (file:/home/devlooj/.sdkman/candidates/maven/current/lib/guava-32.0.1-jre.jar)
WARNING: Please consider reporting this to the maintainers of class com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper
WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] hibernateOrphanRemoval                                             [pom]
[INFO] hibernate6                                                         [jar]
[INFO] hibernate7                                                         [jar]
[INFO]
[INFO] ------------------< be.eforge:hibernateOrphanRemoval >------------------
[INFO] Building hibernateOrphanRemoval 1.0-SNAPSHOT                       [1/3]
[INFO]   from pom.xml
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ hibernateOrphanRemoval ---
[INFO]
[INFO] ------------------------< be.eforge:hibernate6 >------------------------
[INFO] Building hibernate6 1.0-SNAPSHOT                                   [2/3]
[INFO]   from hibernate6/pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ hibernate6 ---
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ hibernate6 ---
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO]
[INFO] --- compiler:3.11.0:compile (default-compile) @ hibernate6 ---
[INFO] Changes detected - recompiling the module! :source
[INFO] Compiling 2 source files with javac [debug target 25] to target/classes
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ hibernate6 ---
[INFO] skip non existing resourceDirectory /home/devlooj/IdeaProjects/robaws/hibernateOrphanRemoval/hibernate6/src/test/resources
[INFO]
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ hibernate6 ---
[INFO] Changes detected - recompiling the module! :dependency
[INFO] Compiling 1 source file with javac [debug target 25] to target/test-classes
[INFO]
[INFO] --- surefire:3.2.2:test (default-test) @ hibernate6 ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running DetachTest
Jul 03, 2026 8:35:09 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [name: pu]
Jul 03, 2026 8:35:09 AM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.6.53.Final
Jul 03, 2026 8:35:09 AM org.hibernate.cache.internal.RegionFactoryInitiator initiateService
INFO: HHH000026: Second-level cache disabled
Jul 03, 2026 8:35:09 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Jul 03, 2026 8:35:09 AM org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator logConnectionInfo
INFO: HHH10001005: Database info:
        Database JDBC URL [jdbc:h2:mem:t;DB_CLOSE_DELAY=-1]
        Database driver: org.h2.Driver
        Database version: 2.3.232
        Autocommit mode: false
        Isolation level: undefined/unknown
        Minimum pool size: 1
        Maximum pool size: 20
Hibernate: create global temporary table HTE_DetachParent(rn_ integer not null, id bigint, primary key (rn_)) TRANSACTIONAL
Hibernate: create global temporary table HTE_DetachChild(rn_ integer not null, id bigint, parent_id bigint, primary key (rn_)) TRANSACTIONAL
Jul 03, 2026 8:35:10 AM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Hibernate: drop table if exists DetachChild cascade
Jul 03, 2026 8:35:10 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@147cc940] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: drop table if exists DetachParent cascade
Hibernate: drop sequence if exists DetachChild_SEQ
Hibernate: drop sequence if exists DetachParent_SEQ
Hibernate: create sequence DetachChild_SEQ start with 1 increment by 50
Jul 03, 2026 8:35:10 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@6562cc23] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: create sequence DetachParent_SEQ start with 1 increment by 50
Hibernate: create table DetachChild (id bigint not null, parent_id bigint, primary key (id))
Hibernate: create table DetachParent (id bigint not null, primary key (id))
Hibernate: alter table if exists DetachChild add constraint FK2bi4x2h6r50llqyorusw6g2rh foreign key (parent_id) references DetachParent
Hibernate: select next value for DetachParent_SEQ
Hibernate: select next value for DetachChild_SEQ
Hibernate: insert into DetachParent (id) values (?)
Hibernate: insert into DetachChild (parent_id,id) values (?,?)
[tx2] em.contains(parent) BEFORE merge = true
Hibernate: delete from DetachChild where id=?
Hibernate: drop table if exists DetachChild cascade
Jul 03, 2026 8:35:10 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@7bede4ea] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: drop table if exists DetachParent cascade
Hibernate: drop sequence if exists DetachChild_SEQ
Hibernate: drop sequence if exists DetachParent_SEQ
Jul 03, 2026 8:35:10 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [name: pu]
Jul 03, 2026 8:35:10 AM org.hibernate.cache.internal.RegionFactoryInitiator initiateService
INFO: HHH000026: Second-level cache disabled
Jul 03, 2026 8:35:10 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Jul 03, 2026 8:35:10 AM org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator logConnectionInfo
INFO: HHH10001005: Database info:
        Database JDBC URL [jdbc:h2:mem:t;DB_CLOSE_DELAY=-1]
        Database driver: org.h2.Driver
        Database version: 2.3.232
        Autocommit mode: false
        Isolation level: undefined/unknown
        Minimum pool size: 1
        Maximum pool size: 20
Hibernate: create global temporary table HTE_DetachParent(rn_ integer not null, id bigint, primary key (rn_)) TRANSACTIONAL
Hibernate: create global temporary table HTE_DetachChild(rn_ integer not null, id bigint, parent_id bigint, primary key (rn_)) TRANSACTIONAL
Jul 03, 2026 8:35:10 AM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Hibernate: drop table if exists DetachChild cascade
Jul 03, 2026 8:35:10 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@7e2c6702] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: drop table if exists DetachParent cascade
Hibernate: drop sequence if exists DetachChild_SEQ
Hibernate: drop sequence if exists DetachParent_SEQ
Hibernate: create sequence DetachChild_SEQ start with 1 increment by 50
Jul 03, 2026 8:35:10 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@5fb7ab9c] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: create sequence DetachParent_SEQ start with 1 increment by 50
Hibernate: create table DetachChild (id bigint not null, parent_id bigint, primary key (id))
Hibernate: create table DetachParent (id bigint not null, primary key (id))
Hibernate: alter table if exists DetachChild add constraint FK2bi4x2h6r50llqyorusw6g2rh foreign key (parent_id) references DetachParent
Hibernate: select next value for DetachParent_SEQ
Hibernate: select next value for DetachChild_SEQ
Hibernate: insert into DetachParent (id) values (?)
Hibernate: insert into DetachChild (parent_id,id) values (?,?)
[tx2] em.contains(parent) BEFORE merge = true
Hibernate: select next value for DetachChild_SEQ
Hibernate: insert into DetachChild (parent_id,id) values (?,?)
Hibernate: delete from DetachChild where id=?
Hibernate: drop table if exists DetachChild cascade
Jul 03, 2026 8:35:10 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@4d43a1b7] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: drop table if exists DetachParent cascade
Hibernate: drop sequence if exists DetachChild_SEQ
Hibernate: drop sequence if exists DetachParent_SEQ
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.093 s -- in DetachTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] ------------------------< be.eforge:hibernate7 >------------------------
[INFO] Building hibernate7 1.0-SNAPSHOT                                   [3/3]
[INFO]   from hibernate7/pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.2.0:clean (default-clean) @ hibernate7 ---
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ hibernate7 ---
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO]
[INFO] --- compiler:3.11.0:compile (default-compile) @ hibernate7 ---
[INFO] Changes detected - recompiling the module! :source
[INFO] Compiling 3 source files with javac [debug target 25] to target/classes
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ hibernate7 ---
[INFO] skip non existing resourceDirectory /home/devlooj/IdeaProjects/robaws/hibernateOrphanRemoval/hibernate7/src/test/resources
[INFO]
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ hibernate7 ---
[INFO] Changes detected - recompiling the module! :dependency
[INFO] Compiling 1 source file with javac [debug target 25] to target/test-classes
[INFO]
[INFO] --- surefire:3.2.2:test (default-test) @ hibernate7 ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running DetachTest
Jul 03, 2026 8:35:10 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH008540: Processing PersistenceUnitInfo [name: pu]
Jul 03, 2026 8:35:10 AM org.hibernate.Version logVersion
INFO: HHH000001: Hibernate ORM core version 7.2.19.Final
Jul 03, 2026 8:35:11 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProvider configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Jul 03, 2026 8:35:11 AM org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator logConnectionInfo
INFO: HHH10001005: Database info:
        Database JDBC URL [jdbc:h2:mem:t;DB_CLOSE_DELAY=-1]
        Database driver: H2 JDBC Driver
        Database dialect: H2Dialect
        Database version: 2.3.232
        Default catalog/schema: T/PUBLIC
        Autocommit mode: false
        Isolation level: READ_COMMITTED
        JDBC fetch size: 100
        Pool: DriverManagerConnectionProvider
        Minimum pool size: 1
        Maximum pool size: 20
Jul 03, 2026 8:35:11 AM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Hibernate: drop table if exists DetachChild cascade
Hibernate: drop table if exists DetachParent cascade
Hibernate: create table DetachChild (id bigint generated by default as identity, parent_id bigint, primary key (id))
Hibernate: create table DetachParent (id bigint generated by default as identity, primary key (id))
Hibernate: alter table if exists DetachChild add constraint FK2bi4x2h6r50llqyorusw6g2rh foreign key (parent_id) references DetachParent
Hibernate: insert into DetachParent (id) values (default)
Hibernate: insert into DetachChild (parent_id,id) values (?,default)
[tx2] em.contains(parent) BEFORE merge = true
Hibernate: delete from DetachChild where id=?
Hibernate: drop table if exists DetachChild cascade
Hibernate: drop table if exists DetachParent cascade
Jul 03, 2026 8:35:11 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH008540: Processing PersistenceUnitInfo [name: pu]
Jul 03, 2026 8:35:11 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProvider configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Jul 03, 2026 8:35:11 AM org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator logConnectionInfo
INFO: HHH10001005: Database info:
        Database JDBC URL [jdbc:h2:mem:t;DB_CLOSE_DELAY=-1]
        Database driver: H2 JDBC Driver
        Database dialect: H2Dialect
        Database version: 2.3.232
        Default catalog/schema: T/PUBLIC
        Autocommit mode: false
        Isolation level: READ_COMMITTED
        JDBC fetch size: 100
        Pool: DriverManagerConnectionProvider
        Minimum pool size: 1
        Maximum pool size: 20
Jul 03, 2026 8:35:11 AM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
Hibernate: drop table if exists DetachChild cascade
Hibernate: drop table if exists DetachParent cascade
Hibernate: create table DetachChild (id bigint generated by default as identity, parent_id bigint, primary key (id))
Hibernate: create table DetachParent (id bigint generated by default as identity, primary key (id))
Hibernate: alter table if exists DetachChild add constraint FK2bi4x2h6r50llqyorusw6g2rh foreign key (parent_id) references DetachParent
Hibernate: insert into DetachParent (id) values (default)
Hibernate: insert into DetachChild (parent_id,id) values (?,default)
[tx2] em.contains(parent) BEFORE merge = true
Hibernate: insert into DetachChild (parent_id,id) values (?,default)
Hibernate: delete from DetachChild where id=?
Hibernate: drop table if exists DetachChild cascade
Hibernate: drop table if exists DetachParent cascade
[ERROR] Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.156 s <<< FAILURE! -- in DetachTest
[ERROR] DetachTest.mergeOfManagedParentWithClearedOrphanCollection -- Time elapsed: 1.096 s <<< ERROR!
jakarta.persistence.RollbackException: Error while committing the transaction [org.hibernate.DetachedObjectException: Given entity is not associated with the persistence context]
        at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:73)
        at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:92)
        at DetachTest.mergeOfManagedParentWithClearedOrphanCollection(DetachTest.java:26)
        at java.base/java.lang.reflect.Method.invoke(Method.java:565)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
Caused by: java.lang.IllegalArgumentException: org.hibernate.DetachedObjectException: Given entity is not associated with the persistence context
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:153)
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:168)
        at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:174)
        at org.hibernate.internal.SessionImpl.fireDelete(SessionImpl.java:922)
        at org.hibernate.internal.SessionImpl.delete(SessionImpl.java:851)
        at org.hibernate.engine.internal.Cascade.deleteOrphans(Cascade.java:637)
        at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:622)
        at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:489)
        at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:452)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:217)
        at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:158)
        at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:173)
        at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:129)
        at org.hibernate.event.internal.AbstractFlushingEventListener.preFlush(AbstractFlushingEventListener.java:83)
        at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:62)
        at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
        at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:138)
        at org.hibernate.internal.SessionImpl.fireFlush(SessionImpl.java:1484)
        at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:481)
        at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2111)
        at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2033)
        at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:410)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:166)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commitNoRollbackOnly(JdbcResourceLocalTransactionCoordinatorImpl.java:248)
        at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:242)
        at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:89)
        ... 4 more
Caused by: org.hibernate.DetachedObjectException: Given entity is not associated with the persistence context
        at org.hibernate.event.internal.DefaultDeleteEventListener.deleteDetachedEntity(DefaultDeleteEventListener.java:170)
        at org.hibernate.event.internal.DefaultDeleteEventListener.deleteUnmanagedInstance(DefaultDeleteEventListener.java:163)
        at org.hibernate.event.internal.DefaultDeleteEventListener.delete(DefaultDeleteEventListener.java:148)
        at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:84)
        at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:149)
        at org.hibernate.internal.SessionImpl.fireDelete(SessionImpl.java:911)
        ... 26 more

[INFO]
[INFO] Results:
[INFO]
[ERROR] Errors:
[ERROR]   DetachTest.mergeOfManagedParentWithClearedOrphanCollection:26 » Rollback Error while committing the transaction [org.hibernate.DetachedObjectException: Given entity is not associated with the persistence context]
[INFO]
[ERROR] Tests run: 2, Failures: 0, Errors: 1, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for hibernateOrphanRemoval 1.0-SNAPSHOT:
[INFO]
[INFO] hibernateOrphanRemoval ............................. SUCCESS [  0.079 s]
[INFO] hibernate6 ......................................... SUCCESS [  2.214 s]
[INFO] hibernate7 ......................................... FAILURE [  1.635 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.984 s
[INFO] Finished at: 2026-07-03T08:35:11+02:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.2.2:test (default-test) on project hibernate7:
[ERROR]
[ERROR] Please refer to /home/devlooj/IdeaProjects/robaws/hibernateOrphanRemoval/hibernate7/target/surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <args> -rf :hibernate7

Observations while narrowing this down

These are things I saw while debugging; I have not pinned the exact merge step responsible, so I’m reporting them as observations rather than a root-cause claim.

  • The divergence is visible at DefaultDeleteEventListener.delete(), at the getEntry(entity) == null fork:
    • 6.5.2: takes deletePersistentInstance (orphan is still managed).
    • 7.2.19: takes deleteUnmanagedInstancedeleteDetachedEntity → throws under JPA bootstrap.
  • Diffing 6.5.2 vs 7.2.19, the following are effectively identical (so the change seems to be elsewhere): the delete() fork itself, CollectionType.preserveSnapshot / createListSnapshot, and EntityType.replaceresolveresolveIdentifier.
  • Runtime probe: right before the merge, em.contains(child) == true; by the time orphan removal runs, there is no managed entity for the child’s key in the persistence context. So the previously-managed child appears to be de-registered from the context during merge. persist() does not cause this.

That points upstream of the delete listener. It has to be somewhere in the merge handling for an already-managed parent with an emptied orphanRemoval collection. I couldn’t identify the precise step that removes the child’s EntityEntry.

Is this an intended behavior change or a regression? Is it part of 7.0 Migration Guide ? If it’s a bug I’m happy to open an HHH issue with this reproduction, and can attempt a PR. I searched the forum and JIRA and didn’t find an existing report, but pointers to a duplicate are welcome.

I forgot to add: when adding a new child after clearing the list, the DeleteListener takes the managed code path when deleting the previous entity.

Not calling the .merge after clearing the list avoids the problem.

My issue is that Spring Data expects a save (because the JDBC flow does not do dirty tracking). Our codebase is following that rule.

Please try to create a reproducer with our test case template and if you are able to reproduce the issue, create a bug ticket in our issue tracker and attach that reproducer.

Hey Beikov

I don’t know what is wrong with atlassian. I cannot seem to login and create an issue. It bounces me back from my google login and then the create button doesn’t even do anything anymore.
I’ve forked the repository and added the same test in both hibernate 6 and hibernate 7.

Hey, there’s a known issue with Jira .. see this thread on how to deal with this: #hibernate-user > Jira issue creation @ :speech_balloon:

So I’ve tried the following:

  • Google account from my normal org => keep redirecting, sometimes says to refresh, then I am not logged in anymore. Sometimes the button doesn’t do anything
  • Created a new account through sign up => Not redirected, dialog keeps saying I need to log in => space is empty when I go back through the link.

Seems like I cannot make a ticket at all… Is there any way I can discuss this differently?

Edit: the “log in” after being logged in worked with my newly created account and I’ve joined the space.

I’ve filed a bug ticket Jira