{"record":{"id":"fa2f0337082b9639","repo":"hibernate/hibernate-orm","slug":"deleted-object-would-be-re-saved-by-cascade-remov","errorCode":null,"errorMessage":"deleted object would be re-saved by cascade (remove deleted object from associations)","messagePattern":"deleted object would be re-saved by cascade \\(remove deleted object from associations\\)","errorType":"exception","errorClass":"ObjectDeletedException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java","lineNumber":1552,"sourceCode":"\t@Nonnull\n\tpublic Set<EntityManager.Option> getOptions() {\n\t\treturn OptionsHelper.getOptions( this );\n\t}\n\n\t@Override\n\tpublic void forceFlush(@Nonnull EntityEntry entityEntry) {\n\t\tforceFlush( entityEntry.getEntityKey() );\n\t}\n\n\t@Override\n\tpublic void forceFlush(@Nonnull EntityKey key) {\n\t\tif ( SESSION_LOGGER.isTraceEnabled() ) {\n\t\t\tSESSION_LOGGER.flushingToForceDeletion(\n\t\t\t\t\tinfoString( key.getPersister(), key.getIdentifier(), getFactory() ) );\n\t\t}\n\n\t\tif ( persistenceContext.getCascadeLevel() > 0 ) {\n\t\t\tthrow new ObjectDeletedException(\n\t\t\t\t\t\"deleted object would be re-saved by cascade (remove deleted object from associations)\",\n\t\t\t\t\tkey.getIdentifier(),\n\t\t\t\t\tkey.getPersister().getEntityName()\n\t\t\t);\n\t\t}\n\t\tcheckOpenOrWaitingForAutoClose();\n\t\tfireFlush();\n\t}\n\n\t/**\n\t * give the interceptor an opportunity to override the default instantiation\n\t */\n\t@Override\n\t@Nonnull\n\tpublic Object instantiate(@Nonnull EntityPersister persister, @Nullable Object id) {\n\t\tcheckOpenOrWaitingForAutoClose();\n\t\tpulseTransactionCoordinator();\n\t\tObject result = callInterceptorCallback(","sourceCodeStart":1534,"sourceCodeEnd":1570,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java#L1534-L1570","documentation":"When Hibernate must force a flush to push a deletion through (e.g. a subsequent operation needs the row gone), it calls forceFlush(EntityKey). If the session is currently mid-cascade, flushing would re-execute cascades and re-save the just-deleted entity, so Hibernate throws ObjectDeletedException('deleted object would be re-saved by cascade...'). The message names the classic cause: the deleted object is still referenced from an association that cascade-saves it.","triggerScenarios":"session.remove(x) while x is still held in a cascade-persisting collection (e.g. parent.getChildren() still contains x with cascade=ALL), then any operation (delete of the parent, lock, query with auto-flush) triggers forceFlush while cascadeLevel > 0. Also bidirectional relations where the many-to-one side still points at the removed entity.","commonSituations":"Forgetting parent.getChildren().remove(child) before removing child; orphanRemoval=false with cascade=ALL; deleting a child then re-saving the parent in the same transaction; bulk re-save loops that walk collections containing soft-deleted items.","solutions":["Remove the entity from all owning associations before delete: parent.getChildren().remove(child); session.remove(child);","Use orphanRemoval=true on the collection so removal from the collection implies deletion, avoiding manual remove of a still-referenced entity","Check/adjust cascade settings: cascade=REMOVE or orphanRemoval instead of blanket cascade=ALL when children are managed through one side only","Flush immediately after the delete (session.flush()) so later cascade work does not hit the pending deletion"],"exampleFix":"// before\norder.getItems().size(); // cascade=ALL on items\nsession.remove(item);          // still inside order.items\nsession.remove(order);         // forceFlush during cascade -> ObjectDeletedException\n\n// after\norder.getItems().remove(item); // sever association first\nsession.remove(item);\nsession.flush();               // deletion is now safely applied\nsession.remove(order);","handlingStrategy":"try-catch","validationCode":"// Sever associations before deleting, so cascade cannot re-save the entity\nparent.getChildren().remove(child);\nsession.remove(child);\nsession.flush(); // apply deletion before further cascade work","typeGuard":null,"tryCatchPattern":"try {\n    session.remove(entity);\n    session.flush();\n} catch (ObjectDeletedException e) {\n    // entity is still referenced by a cascade-persisting association\n    throw new IllegalStateException(\n        \"Remove '\" + e.getEntityName() + \"' from its parent collection before deleting\", e);\n}","preventionTips":["Always remove the child from the parent collection before (or instead of) deleting it","Prefer orphanRemoval=true so collection removal drives deletion through one path","Avoid blanket cascade=ALL; declare exactly the cascade types each association needs","Flush promptly after deletes so pending deletions do not collide with later cascades"],"tags":["hibernate","cascade","delete","flush","orphan-removal","entity-state"],"backgroundTag":"cascade-resave-deleted-entity","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}