hibernate/hibernate-orm · error · HibernateException
Lock mode ${lockMode} not valid for locking via 'update' sta
Error message
Lock mode ${lockMode} not valid for locking via 'update' statement What it means
AbstractPessimisticUpdateLockingStrategy implements pessimistic locking by issuing an UPDATE ... where id=? and version=? against the row. Such an update can only express a write-level lock, so the constructor rejects any LockMode weaker than PESSIMISTIC_READ with HibernateException 'Lock mode <mode> not valid for locking via 'update' statement'. The strategy is built by dialects whose getLockingStrategy maps lock modes to update-based locking.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/lock/AbstractPessimisticUpdateLockingStrategy.java:42
*/
public abstract class AbstractPessimisticUpdateLockingStrategy implements LockingStrategy {
private final EntityPersister lockable;
private final LockMode lockMode;
private final String sql;
/**
* Construct a locking strategy based on SQL UPDATE statements.
*
* @param lockable The metadata for the entity to be locked.
* @param lockMode Indicates the type of lock to be acquired. Note that
* read-locks are not valid for this strategy.
*/
public AbstractPessimisticUpdateLockingStrategy(EntityPersister lockable, LockMode lockMode) {
this.lockable = lockable;
this.lockMode = lockMode;
if ( lockMode.lessThan( LockMode.PESSIMISTIC_READ ) ) {
throw new HibernateException( "Lock mode " + lockMode
+ " not valid for locking via 'update' statement" );
}
if ( !lockable.isVersioned() ) {
throw new HibernateException( "Entity '" + lockable.getEntityName()
+ "' has no version and may not be locked via 'update' statement" );
}
this.sql = generateLockString();
}
@Override
public void lock(Object id, Object version, Object object, int timeout, SharedSessionContractImplementor session) {
try {
doLock( id, version, session );
}
catch (JDBCException e) {
throw new PessimisticEntityLockException( object, "Could not obtain pessimistic lock", e );
}
}View on GitHub (pinned to fad1729dce)
Solutions
- Request PESSIMISTIC_READ or stronger (usually PESSIMISTIC_WRITE) when the dialect uses update-based locking
- If you maintain a custom dialect, return the update strategy only for PESSIMISTIC_READ/PESSIMISTIC_WRITE/PESSIMISTIC_FORCE_INCREMENT and a select-based strategy otherwise
- Replace deprecated LockMode.READ/UPGRADE usages with their modern equivalents that the dialect maps correctly
- Prefer optimistic (@Version-based) locking for read intents instead of forcing weak pessimistic modes
Example fix
// before session.buildLockRequest(new LockOptions(LockMode.READ)).lock(person); // after session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(person);
Defensive patterns
Strategy: validation
Validate before calling
// Only request modes the strategy accepts
static LockMode sanitizeForUpdateLocking(LockMode requested) {
return requested.lessThan(LockMode.PESSIMISTIC_READ) ? LockMode.PESSIMISTIC_WRITE : requested;
}
session.buildLockRequest(new LockOptions(sanitizeForUpdateLocking(LockMode.READ))).lock(person); Try / catch
try {
session.buildLockRequest(new LockOptions(mode)).lock(person);
}
catch (HibernateException e) {
if (e.getMessage().contains("not valid for locking via 'update' statement")) {
throw new IllegalArgumentException("Use PESSIMISTIC_READ or stronger with update-based locking (got " + mode + ")", e);
}
throw e;
} Prevention
- Standardize on PESSIMISTIC_WRITE for pessimistic lock requests instead of legacy READ/UPGRADE modes
- In custom dialects, branch getLockingStrategy on the mode threshold before returning an update-based strategy
- Ban LockMode.NONE/READ/OPTIMISTIC in code paths that go through session.lock on lock-emulating dialects
When it happens
Trigger: A dialect returns an update-based locking strategy for a weak lock mode and Hibernate constructs the strategy - e.g. session.buildLockRequest(new LockOptions(LockMode.READ)).lock(entity) or session.lock(entity, LockMode.OPTIMISTIC) - while the active dialect uses AbstractPessimisticUpdateLockingStrategy for that mode (lockMode.lessThan(PESSIMISTIC_READ) is true). Custom dialects overriding getLockingStrategy too broadly hit this immediately at strategy construction.
Common situations: Custom dialect implementations that return UpdateLockingStrategy for every requested LockMode; legacy code using old LockMode constants (READ/UPGRADE, now NONE/OPTIMISTIC) on databases where Hibernate emulates locking via UPDATE; upgrading Hibernate versions where deprecated lock modes map differently.
Related errors
- Entity '{}' may not be locked at level {}
- Entity '{}' may not be locked at level {}
- Entity '{}' may not be locked at level {}
- Lock mode {} not valid for locking via 'update' statement
- WRITE is not a valid LockMode as an argument
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/aabf96c93a722707.
Report an issue: GitHub.