{"record":{"id":"42794f1cd3201f2c","repo":"hibernate/hibernate-orm","slug":"entity-may-not-be-locked-at-level-42794f","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/PessimisticForceIncrementLockingStrategy.java","lineNumber":37,"sourceCode":" * @author Scott Marlow\n * @since 3.5\n */\npublic class PessimisticForceIncrementLockingStrategy 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 PessimisticForceIncrementLockingStrategy(EntityPersister lockable, LockMode lockMode) {\n\t\tthis.lockable = lockable;\n\t\tthis.lockMode = lockMode;\n\t\t// ForceIncrement can be used for PESSIMISTIC_READ, PESSIMISTIC_WRITE or PESSIMISTIC_FORCE_INCREMENT\n\t\tif ( lockMode.lessThan( LockMode.PESSIMISTIC_READ ) ) {\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, SharedSessionContractImplementor session) {\n\t\tfinal var entry = session.getPersistenceContextInternal().getEntry( object );\n\t\tOptimisticLockHelper.forceVersionIncrement( object, entry, session );\n\t}\n\n\t/**\n\t * Retrieve the specific lock mode defined.\n\t *\n\t * @return The specific lock mode.","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java#L19-L55","documentation":"PessimisticForceIncrementLockingStrategy immediately forces a version increment while also acting as a pessimistic lock; it accepts PESSIMISTIC_READ, PESSIMISTIC_WRITE and PESSIMISTIC_FORCE_INCREMENT. The constructor throws HibernateException 'Entity '<name>' may not be locked at level <mode>' when lockMode.lessThan(LockMode.PESSIMISTIC_READ), i.e. for OPTIMISTIC or weaker modes routed here. The comment in source spells out the three valid modes.","triggerScenarios":"A dialect's getLockingStrategy (or explicit code) hands this strategy a mode below PESSIMISTIC_READ - e.g. session.lock(entity, LockMode.OPTIMISTIC) resolving to PessimisticForceIncrementLockingStrategy, or direct construction with LockMode.UPGRADE. Thrown eagerly in the constructor with entity name and offending mode.","commonSituations":"Custom dialect getLockingStrategy implementations that map all modes to one strategy class; switching lock constants during a Hibernate major upgrade where LockMode ordering changed; test code constructing strategies with arbitrary modes.","solutions":["Request PESSIMISTIC_READ, PESSIMISTIC_WRITE or PESSIMISTIC_FORCE_INCREMENT with this strategy","Fix custom dialect mode-to-strategy mapping so weaker modes get optimistic or select-based strategies instead","Use LockModeType JPA constants to make the intended strength explicit at call sites"],"exampleFix":"// before\nsession.lock(person, LockMode.OPTIMISTIC); // routed to pessimistic force-increment strategy\n\n// after\nsession.lock(person, LockMode.PESSIMISTIC_FORCE_INCREMENT);","handlingStrategy":"validation","validationCode":"// Force the mode into the accepted range for force-increment locking\nstatic LockMode atLeastPessimisticRead(LockMode m) {\n    return m.lessThan(LockMode.PESSIMISTIC_READ) ? LockMode.PESSIMISTIC_WRITE : m;\n}\nsession.lock(person, atLeastPessimisticRead(requestedMode));","typeGuard":null,"tryCatchPattern":"try {\n    session.lock(person, LockMode.PESSIMISTIC_FORCE_INCREMENT);\n}\ncatch (HibernateException e) {\n    if (e.getMessage().contains(\"may not be locked at level\")) {\n        throw new IllegalArgumentException(\"Use PESSIMISTIC_READ/PESSIMISTIC_WRITE/PESSIMISTIC_FORCE_INCREMENT\", e);\n    }\n    throw e;\n}","preventionTips":["Remember the valid set for PessimisticForceIncrementLockingStrategy: PESSIMISTIC_READ, PESSIMISTIC_WRITE, PESSIMISTIC_FORCE_INCREMENT","Never map optimistic or weaker modes to force-increment strategies in custom dialects","Prefer the JPA LockModeType constants so intent is explicit"],"tags":["hibernate","locking","pessimistic-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"}