hibernate/hibernate-orm · error · HibernateException
Connection lock-timeout does not accept skip-locked
Error message
Connection lock-timeout does not accept skip-locked
What it means
Hibernate 7's CockroachDB support applies pessimistic-lock timeouts at the JDBC connection level: before the locking statement it executes 'set lock_timeout = N' (via Helper.setLockTimeout). The connection setting can only represent a real duration (or 0 = wait forever), so when the requested timeout is the magic value SKIP_LOCKED (-2 ms, Timeouts.SKIP_LOCKED_MILLI) it throws this HibernateException instead of silently applying wrong semantics. CockroachLockingSupport reports Level.SUPPORTED (not EXTENDED), meaning neither skip-locked nor no-wait is expressible through this path.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/CockroachLockingSupport.java:107
default -> Timeout.milliseconds( millis );
};
},
connection,
factory
);
}
@Override
public void setLockTimeout(
Timeout timeout,
Connection connection,
SessionFactoryImplementor factory) {
Helper.setLockTimeout(
timeout,
(t) -> {
final int milliseconds = timeout.milliseconds();
if ( milliseconds == SKIP_LOCKED_MILLI ) {
throw new HibernateException( "Connection lock-timeout does not accept skip-locked" );
}
if ( milliseconds == NO_WAIT_MILLI ) {
throw new HibernateException( "Connection lock-timeout does not accept no-wait" );
}
return milliseconds == WAIT_FOREVER_MILLI ? 0 : milliseconds;
},
"set lock_timeout = %s",
connection,
factory
);
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Use a real positive timeout (e.g. lockOptions.setTimeOut(1000) or Timeouts.ONE_SECOND) or WAIT_FOREVER (-1) on CockroachDB
- If you need skip-locked semantics, request them at the locking-clause level (FOR UPDATE SKIP LOCKED) rather than through the connection lock_timeout, or use a native query
- Guard up front: dialect.getLockingSupport().getConnectionLockTimeoutStrategy().getSupportedLevel() - skip-locked is accepted by no level, no-wait only by Level.EXTENDED
- Remove or scope down global lock timeout hints set to -2/0 in persistence.xml or Spring Data JPA hints
Example fix
// before
Map<String, Object> hints = Map.of("jakarta.persistence.lock.timeout", -2); // SKIP_LOCKED
Order o = em.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE, hints);
// after: a real wait; skip-locked is not expressible via CRDB connection lock_timeout
Map<String, Object> hints = Map.of("jakarta.persistence.lock.timeout", 1000);
Order o = em.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE, hints); Defensive patterns
Strategy: validation
Validate before calling
ConnectionLockTimeoutStrategy s = sessionFactory.getJdbcServices().getDialect()
.getLockingSupport().getConnectionLockTimeoutStrategy();
int millis = lockOptions.getTimeOut();
if (millis == Timeouts.SKIP_LOCKED_MILLI) {
lockOptions.setTimeOut(50); // skip-locked is never expressible via connection lock_timeout
} Type guard
static boolean acceptsConnectionTimeout(ConnectionLockTimeoutStrategy s, int millis) {
if (s.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.NONE) return false;
if (millis == Timeouts.SKIP_LOCKED_MILLI) return false;
return millis != Timeouts.NO_WAIT_MILLI
|| s.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.EXTENDED;
} Try / catch
try {
session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE).timeout(1000)).lock(entity);
} catch (HibernateException e) {
if (e.getMessage() != null && e.getMessage().contains("lock-timeout does not accept")) {
// requested magic timeout not supported by this dialect: degrade to a real timeout
} else { throw e; }
} Prevention
- Never set 'jakarta.persistence.lock.timeout' (or LockOptions) to -2 (skip-locked) when the dialect applies timeouts on the connection
- Keep lock timeout configuration per-dialect, not global in persistence.xml
- Exercise pessimistic locking paths in integration tests on every supported database
- Check getConnectionLockTimeoutStrategy().getSupportedLevel() at startup and log it
When it happens
Trigger: session.buildLockRequest(LockOptions.UPGRADE_SKIPLOCKED).lock(entity) or LockOptions.setTimeOut(-2); a query with setLockMode(LockModeType.PESSIMISTIC_WRITE) plus hint 'jakarta.persistence.lock.timeout' (or legacy 'javax.persistence.lock.timeout') set to -2; any Timeouts.SKIP_LOCKED Timeout that reaches CockroachLockingSupport.setLockTimeout when LockTimeoutType.CONNECTION was selected (JdbcSelectWithActions registers LockTimeoutHandler).
Common situations: Porting PostgreSQL pessimistic-locking code to CockroachDB; a global <property name="jakarta.persistence.lock.timeout" value="-2"/> in persistence.xml applied to every lock; code that works on SQL Server (Level.EXTENDED) reused on CockroachDB; upgrading from Hibernate 6 where these timeout values were handled by different machinery.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Connection lock-timeout does not accept skip-locked
- Connection lock-timeout does not accept no-wait
- Connection lock-timeout does not accept skip-locked
- Connection lock-timeout does not accept skip-locked
- Connection lock-timeout does not accept skip-locked
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/f8409d664702bc71.
Report an issue: GitHub.