{"record":{"id":"98f3c08a67506a1a","repo":"hibernate/hibernate-orm","slug":"entity-may-not-be-locked-at-level-98f3c0","errorCode":null,"errorMessage":"Entity '{}' may not be locked at level {}","messagePattern":"Entity '(.+?)' may not be locked at level (.+?)","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticLockingStrategy.java","lineNumber":36,"sourceCode":" *\n * @author Scott Marlow\n * @since 3.5\n */\npublic class OptimisticLockingStrategy implements LockingStrategy {\n\tprivate final EntityPersister lockable;\n\tprivate final LockMode lockMode;\n\n\t/**\n\t * Construct locking strategy.\n\t *\n\t * @param lockable The metadata for the entity to be locked.\n\t * @param lockMode Indicates the type of lock to be acquired.\n\t */\n\tpublic OptimisticLockingStrategy(EntityPersister lockable, LockMode lockMode) {\n\t\tthis.lockable = lockable;\n\t\tthis.lockMode = lockMode;\n\t\tif ( lockMode.lessThan( LockMode.OPTIMISTIC ) ) {\n\t\t\tthrow new HibernateException( \"Entity '\" + lockable.getEntityName()\n\t\t\t\t\t\t+ \"' may not be locked at level \" + lockMode );\n\t\t}\n\t\tif ( !lockable.isVersioned() ) {\n\t\t\tthrow new HibernateException( \"Entity '\" + lockable.getEntityName()\n\t\t\t\t\t\t+ \"' has no version and may not be locked at level \" + lockMode);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void lock(Object id, Object version, Object object, int timeout, EventSource session) {\n\t\t// Register the EntityVerifyVersionProcess action to run just prior to transaction commit.\n\t\tsession.getActionQueue().registerCallback( new EntityVerifyVersionProcess( object ) );\n\t}\n\n\tprotected LockMode getLockMode() {\n\t\treturn lockMode;\n\t}\n}","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticLockingStrategy.java#L18-L54","documentation":"OptimisticLockingStrategy verifies the entity version at transaction commit and is only valid for lock modes at or above LockMode.OPTIMISTIC. The constructor throws HibernateException 'Entity '<name>' may not be locked at level <mode>' when lockMode.lessThan(LockMode.OPTIMISTIC), i.e. for NONE/READ-style modes. Dialects create this strategy from getLockingStrategy, so the failure indicates a weaker mode was routed here.","triggerScenarios":"session.lock(entity, LockMode.READ) (legacy constant) or LockMode.NONE with a dialect that resolves those modes to OptimisticLockingStrategy; explicit new OptimisticLockingStrategy(persister, LockMode.READ) in custom code. Thrown eagerly in the constructor at strategy construction time.","commonSituations":"Old code bases still using pre-JPA LockMode.READ/UPGRADE constants after a Hibernate upgrade changed mode mappings; custom dialects whose getLockingStrategy switch statement was copied from an old version; direct strategy instantiation in tests.","solutions":["Use LockMode.OPTIMISTIC (JPA: LockModeType.OPTIMISTIC) or stronger with this strategy","Update custom dialect getLockingStrategy mappings so weak modes never reach OptimisticLockingStrategy","Replace deprecated LockMode constants (READ, UPGRADE) with their modern equivalents across the code base"],"exampleFix":"// before\nsession.lock(person, LockMode.READ);\n\n// after\nsession.lock(person, LockMode.OPTIMISTIC);","handlingStrategy":"validation","validationCode":"// Ensure the mode is at least OPTIMISTIC before locking\nstatic LockMode atLeastOptimistic(LockMode m) {\n    return m.lessThan(LockMode.OPTIMISTIC) ? LockMode.OPTIMISTIC : m;\n}\nsession.lock(person, atLeastOptimistic(requestedMode));","typeGuard":null,"tryCatchPattern":"try {\n    session.lock(person, LockMode.OPTIMISTIC);\n}\ncatch (HibernateException e) {\n    if (e.getMessage().contains(\"may not be locked at level\")) {\n        throw new IllegalArgumentException(\"Use LockMode.OPTIMISTIC or stronger (got a weaker/legacy mode)\", e);\n    }\n    throw e;\n}","preventionTips":["Replace legacy LockMode.READ/UPGRADE with OPTIMISTIC/PESSIMISTIC_WRITE across the code base","In custom dialect getLockingStrategy, never route modes below OPTIMISTIC to OptimisticLockingStrategy","Run a migration lint (grep for LockMode.READ/UPGRADE) during Hibernate major upgrades"],"tags":["hibernate","locking","optimistic-lock","lock-mode","dialect"],"backgroundTag":"invalid-lock-mode","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}