{"record":{"id":"9eabfea707d356ac","repo":"hibernate/hibernate-orm","slug":"given-entity-was-removed","errorCode":null,"errorMessage":"Given entity was removed","messagePattern":"Given entity was removed","errorType":"exception","errorClass":"ObjectDeletedException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java","lineNumber":559,"sourceCode":"\t@Override\n\tpublic LockMode getCurrentLockMode(Object object) {\n\t\tcheckOpen();\n\t\tcheckTransactionSyncStatus();\n\t\tif ( object == null ) {\n\t\t\tthrow new NullPointerException( \"null object passed to getCurrentLockMode()\" );\n\t\t}\n\n\t\tfinal var lazyInitializer = extractLazyInitializer( object );\n\t\tif ( lazyInitializer != null ) {\n\t\t\tobject = lazyInitializer.getImplementation( this );\n\t\t\tif ( object == null ) {\n\t\t\t\treturn LockMode.NONE;\n\t\t\t}\n\t\t}\n\n\t\tfinal var entry = getEntityEntry( object );\n\t\tif ( entry.getStatus().isDeletedOrGone() ) {\n\t\t\tthrow new ObjectDeletedException( \"Given entity was removed\", entry.getId(),\n\t\t\t\t\tentry.getPersister().getEntityName() );\n\t\t}\n\t\telse {\n\t\t\treturn entry.getLockMode();\n\t\t}\n\t}\n\n\t@Override\n\tpublic Object getEntityUsingInterceptor(@Nonnull EntityKey key) {\n\t\tcheckOpenOrWaitingForAutoClose();\n\t\t// todo : should this get moved to PersistentContext?\n\t\t// logically, is PersistentContext the \"thing\" to which an interceptor gets attached?\n\t\tfinal Object result = persistenceContext.getEntity( key );\n\t\tif ( result == null ) {\n\t\t\tfinal Object newObject = callInterceptorCallback(\n\t\t\t\t\t() -> getInterceptor().getEntity( key.getEntityName(), key.getIdentifier() ) );\n\t\t\tif ( newObject != null ) {\n\t\t\t\tlock( newObject, LockMode.NONE );","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java#L541-L577","documentation":"getCurrentLockMode() reads the EntityEntry of the object; if its status is DELETED/GONE the entity has been removed in this session (remove() scheduled or already flushed), and Hibernate throws ObjectDeletedException('Given entity was removed'). A deleted entity has no ongoing lock semantics — asking for its lock mode is a state error, not a missing-data error.","triggerScenarios":"Calling session.getCurrentLockMode(entity) after session.remove(entity) (or orphanRemoval marking it) within the same session/transaction, before or after flush. Also via cascade-delete: a child deleted by cascade then queried for lock mode.","commonSituations":"Audit/logging code that records lock modes for all processed entities and runs after a delete branch; generic frameworks intercepting remove() and then inspecting lock state; flows where the same object instance is reused for delete and later inspection in one transaction.","solutions":["Skip lock inspection for removed entities: check entry status via session.getPersistenceContext().getEntry(obj) or track removed identities in a Set","Reorder the flow: capture getCurrentLockMode() before remove(), not after","If the entity must survive, avoid the remove or clear/reattach a different instance","Catch ObjectDeletedException in generic monitoring code and treat it as 'no lock mode (deleted)'"],"exampleFix":"// before\nsession.remove(order);\nlogLock(session.getCurrentLockMode(order)); // ObjectDeletedException\n\n// after\nLockMode mode = session.getCurrentLockMode(order); // inspect first\nsession.remove(order);\nlogLock(mode);","handlingStrategy":"try-catch","validationCode":"// Skip deleted entities before asking for their lock mode\nEntityEntry entry = session.getPersistenceContext().getEntry(object);\nif (entry == null || entry.getStatus().isDeletedOrGone()) {\n    return LockMode.NONE; // or skip audit record\n}\nreturn session.getCurrentLockMode(object);","typeGuard":null,"tryCatchPattern":"try {\n    return session.getCurrentLockMode(object);\n} catch (ObjectDeletedException e) {\n    // entity already removed in this session — no lock mode exists\n    LOG.debug(\"lock mode requested for deleted entity {}\", e.getEntityName());\n    return LockMode.NONE;\n}","preventionTips":["Inspect lock modes before remove(), not after","Track removed entities in a Set when audit code runs after delete branches","In generic frameworks, treat ObjectDeletedException as a normal 'no state' signal rather than an error"],"tags":["hibernate","session","lock-mode","deleted-entity","object-deleted-exception","entity-state"],"backgroundTag":"entity-state-conflict","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}