hibernate/hibernate-orm · error · HibernateException
Entity '{}' may not be locked at level {}
Error message
Entity '{}' may not be locked at level {} What it means
OptimisticForceIncrementLockingStrategy implements locking by scheduling a version increment at transaction commit, which only makes sense for modes at or above OPTIMISTIC_FORCE_INCREMENT. Its constructor throws HibernateException 'Entity '<name>' may not be locked at level <mode>' when lockMode.lessThan(LockMode.OPTIMISTIC_FORCE_INCREMENT). The strategy is normally produced by a dialect's getLockingStrategy, so the exception means that mapping handed a weaker mode (OPTIMISTIC, READ, NONE) to this class.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticForceIncrementLockingStrategy.java:37
*
* @author Scott Marlow
* @since 3.5
*/
public class OptimisticForceIncrementLockingStrategy implements LockingStrategy {
private final EntityPersister lockable;
private final LockMode lockMode;
/**
* Construct locking strategy.
*
* @param lockable The metadata for the entity to be locked.
* @param lockMode Indicates the type of lock to be acquired.
*/
public OptimisticForceIncrementLockingStrategy(EntityPersister lockable, LockMode lockMode) {
this.lockable = lockable;
this.lockMode = lockMode;
if ( lockMode.lessThan( LockMode.OPTIMISTIC_FORCE_INCREMENT ) ) {
throw new HibernateException( "Entity '" + lockable.getEntityName()
+ "' may not be locked at level " + lockMode );
}
if ( !lockable.isVersioned() ) {
throw new HibernateException( "Entity '" + lockable.getEntityName()
+ "' has no version and may not be locked at level " + lockMode);
}
}
@Override
public void lock(Object id, Object version, Object object, int timeout, EventSource session) {
// final EntityEntry entry = session.getPersistenceContextInternal().getEntry( object );
// Register the EntityIncrementVersionProcess action to run just prior to transaction commit.
session.getActionQueue().registerCallback( new EntityIncrementVersionProcess( object ) );
}
protected LockMode getLockMode() {
return lockMode;
}View on GitHub (pinned to fad1729dce)
Solutions
- Pass LockMode.OPTIMISTIC_FORCE_INCREMENT (or stronger) wherever this strategy is used - e.g. session.lock(entity, LockMode.OPTIMISTIC_FORCE_INCREMENT)
- In a custom dialect, return OptimisticLockingStrategy for OPTIMISTIC and OptimisticForceIncrementLockingStrategy only for OPTIMISTIC_FORCE_INCREMENT and above
- Prefer the JPA constants (LockModeType.OPTIMISTIC_FORCE_INCREMENT) so the mode is explicit at call sites
Example fix
// before session.lock(person, LockMode.OPTIMISTIC); // dialect maps this to force-increment strategy // after session.lock(person, LockMode.OPTIMISTIC_FORCE_INCREMENT);
Defensive patterns
Strategy: validation
Validate before calling
// Keep mode and strategy aligned before locking
static LockMode forOptimisticForceIncrement(LockMode m) {
return m.lessThan(LockMode.OPTIMISTIC_FORCE_INCREMENT) ? LockMode.OPTIMISTIC_FORCE_INCREMENT : m;
}
session.lock(person, forOptimisticForceIncrement(requestedMode)); Try / catch
try {
session.lock(person, LockMode.OPTIMISTIC_FORCE_INCREMENT);
}
catch (HibernateException e) {
if (e.getMessage().contains("may not be locked at level")) {
throw new IllegalArgumentException("Use OPTIMISTIC_FORCE_INCREMENT or stronger with this strategy", e);
}
throw e;
} Prevention
- Use JPA LockModeType.OPTIMISTIC_FORCE_INCREMENT explicitly at call sites
- In custom dialects, map modes to strategies with a threshold check (never below OPTIMISTIC_FORCE_INCREMENT for this class)
- Prefer built-in dialect mappings over hand-rolled getLockingStrategy overrides
When it happens
Trigger: A dialect (or explicit code) constructs OptimisticForceIncrementLockingStrategy with LockMode.OPTIMISTIC or any weaker mode - e.g. session.lock(entity, LockMode.OPTIMISTIC) where the dialect resolves that mode to the force-increment strategy, or new OptimisticForceIncrementLockingStrategy(persister, LockMode.READ) in custom dialect code. The exception is thrown eagerly at strategy construction.
Common situations: Custom dialects overriding getLockingStrategy without re-checking the mode threshold; refactoring lock requests from PESSIMISTIC_* to OPTIMISTIC while the dialect mapping stayed on force-increment; unit tests constructing strategies directly with arbitrary modes.
Related errors
- Entity '{}' may not be locked at level {}
- Lock mode ${lockMode} not valid for locking via 'update' sta
- Entity '{}' may not be locked at level {}
- WRITE is not a valid LockMode as an argument
- Optimistic locking strategies not supported in stateless ses
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/cc3bc3d0a11876b3.
Report an issue: GitHub.