{"record":{"id":"b15120fcb62ac72d","repo":"hibernate/hibernate-orm","slug":"persistence-context-contains-a-more-recent-version","errorCode":null,"errorMessage":"Persistence context contains a more recent version of the given entity","messagePattern":"Persistence context contains a more recent version of the given entity","errorType":"exception","errorClass":"StaleObjectStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java","lineNumber":236,"sourceCode":"\t\t\t@Nonnull EventSource source) {\n\t\tfinal var persistenceContext = source.getPersistenceContextInternal();\n\t\tfinal Object existingEntity = persistenceContext.getEntity( key );\n\t\tif ( existingEntity != null ) {\n\t\t\tif ( persistenceContext.getEntry( existingEntity ).getStatus().isDeletedOrGone() ) {\n\t\t\t\t// already deleted, no work to do\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tEVENT_LISTENER_LOGGER.flushAndEvictOnRemove( key.getEntityName() );\n\t\t\t\tsource.flush();\n\t\t\t\tif ( !persister.isVersioned()\n\t\t\t\t\t\t|| persister.getVersionType()\n\t\t\t\t\t\t\t\t.isEqual( version, persister.getVersion( existingEntity ) ) ) {\n\t\t\t\t\tsource.evict( existingEntity );\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new StaleObjectStateException( key.getEntityName(), key.getIdentifier(),\n\t\t\t\t\t\t\t\"Persistence context contains a more recent version of the given entity\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate void deletePersistentInstance(\n\t\t\t@Nonnull DeleteEvent event,\n\t\t\t@Nonnull DeleteContext transientEntities,\n\t\t\t@Nonnull Object entity,\n\t\t\t@Nonnull EntityEntry entityEntry) {\n\t\tEVENT_LISTENER_LOGGER.deletingPersistentInstance();\n\t\tfinal var source = event.getSession();\n\t\tif ( entityEntry.getStatus().isDeletedOrGone()\n\t\t\t\t|| source.getPersistenceContextInternal()","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java#L218-L254","documentation":"While deleting a detached entity, flushAndEvictExistingEntity() finds a managed instance under the same key in the persistence context, flushes, and compares versions: the managed copy's version differs, so the detached copy you passed is stale. Hibernate throws StaleObjectStateException('Persistence context contains a more recent version of the given entity') — optimistic locking applied on the remove path.","triggerScenarios":"session.remove(detachedEntity) while the same session manages a newer version of that row (loaded after your detached copy was read); a detached instance built from stale state mixed back into an active session; two loads of the same row in one conversation with a bump in between.","commonSituations":"Long conversations with detached reattachment; delete flows fed by cached/stale frontend state while background jobs bumped the version; optimistic-lock @Version columns added to entities used in delete paths.","solutions":["Use merge() before remove so the version is reconciled against the managed copy","Re-fetch fresh state in the current session and delete that: session.remove(session.find(X.class, id))","Catch StaleObjectStateException and either retry the unit of work from fresh state or report a conflict","Avoid carrying detached instances across long conversations without version checks"],"exampleFix":"// before\nsession.remove(staleOrder); // session manages a newer version -> StaleObjectStateException\n\n// after\nOrder fresh = session.find(Order.class, staleOrder.getId());\nsession.remove(fresh);","handlingStrategy":"retry","validationCode":"// avoid the stale path: delete the managed, most recent version\nOrder fresh = session.find(Order.class, detached.getId());\nif (fresh != null) {\n    session.remove(fresh);\n}","typeGuard":null,"tryCatchPattern":"try {\n    session.remove(detachedOrder);\n} catch (StaleObjectStateException e) {\n    // persistence context has a newer version: reload fresh state and retry once\n    Order fresh = session.find(Order.class, detachedOrder.getId());\n    session.remove(fresh);\n}","preventionTips":["merge() before remove() so versions are reconciled","Re-fetch entities inside the transaction that deletes them","Keep sessions/transactions short when @Version columns are used","Handle StaleObjectStateException explicitly at the use-case boundary"],"tags":["optimistic-locking","delete","versioning","session"],"backgroundTag":"optimistic-lock-conflict","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}