hibernate/hibernate-orm · error · UnsupportedOperationException
Spanner does not support lock timeout.
Error message
Spanner does not support lock timeout.
What it means
SpannerDialect.validateSpannerLockTimeout(int millis) throws UnsupportedOperationException('Spanner does not support lock timeout.') when Timeouts.isRealTimeout(millis) is true — i.e. a positive millisecond wait was requested. Cloud Spanner's FOR UPDATE has no WAIT n / NOWAIT / SKIP LOCKED modifiers, so any concrete timeout is impossible; only the sentinel 'no timeout' value is accepted. The validator runs inside getReadLockString/getWriteLockString before SQL is built.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java:1294
@Override
public String getForUpdateNowaitString(String aliases) {
throw new UnsupportedOperationException( "Spanner does not support no wait." );
}
@Override
public String getForUpdateSkipLockedString() {
throw new UnsupportedOperationException( "Spanner does not support skip locked." );
}
@Override
public String getForUpdateSkipLockedString(String aliases) {
throw new UnsupportedOperationException( "Spanner does not support skip locked." );
}
private static void validateSpannerLockTimeout(int millis) {
if ( Timeouts.isRealTimeout( millis ) ) {
throw new UnsupportedOperationException( "Spanner does not support lock timeout." );
}
if ( millis == Timeouts.SKIP_LOCKED_MILLI ) {
throw new UnsupportedOperationException( "Spanner does not support skip locked." );
}
if ( millis == Timeouts.NO_WAIT_MILLI ) {
throw new UnsupportedOperationException( "Spanner does not support no wait." );
}
}
@Override
public boolean supportsOffsetInSubquery() {
return true;
}
@Override
public char openQuote() {
return '`';
}View on GitHub (pinned to fad1729dce)
Solutions
- Remove the positive lock timeout property/hint — leave it unset (or 0/no-timeout semantics) so FOR UPDATE renders without modifiers.
- Bound waits at the transaction level instead: set a Spanner transaction timeout (e.g. spring.transaction.default-timeout or the driver's transaction options).
- Catch UnsupportedOperationException around locking calls as a safety net and retry without the timeout.
- Prefer optimistic @Version locking when wait bounding was the only goal.
Example fix
# before spring.jpa.properties.jakarta.persistence.lock.timeout=5000 # after (remove; Spanner FOR UPDATE supports no timeout modifier) # spring.jpa.properties.jakarta.persistence.lock.timeout= <- unset
Defensive patterns
Strategy: validation
Validate before calling
int t = lockOptions.getTimeOut();
if (Timeouts.isRealTimeout(t) && (dialect instanceof SpannerDialect || dialect instanceof SpannerPostgreSQLDialect)) {
lockOptions.setTimeOut(LockOptions.NO_TIMEOUT);
} Try / catch
try { return session.find(Order.class, id, lockOptions); }
catch (UnsupportedOperationException e) {
if (e.getMessage().contains("lock timeout")) { /* retry with no timeout; bound via transaction timeout */ }
throw e;
} Prevention
- Do not set positive lock.timeout values on Spanner.
- Bound waits with transaction/driver timeouts instead.
- Keep JPA hint files per-datasource.
When it happens
Trigger: Setting jakarta.persistence.lock.timeout=5000 (or Spring @QueryHint lock.timeout, or LockOptions.setTimeOut(5000)) with pessimistic locking on a Spanner connection; the value reaches validateSpannerLockTimeout via getReadLockString(timeout.milliseconds()) and throws.
Common situations: Copy-pasted JPA properties from other databases where a lock wait limit is standard ops practice; Spring @Lock(PESSIMISTIC_WRITE) repositories with a timeout hint; attempts to bound lock waits to avoid long transaction aborts on Spanner.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Spanner does not support no wait.
- Spanner does not support skip locked.
- Spanner does not support lock timeout.
- Spanner doesn't support for-update with no-wait timeout
- Spanner doesn't support for-update with skip locked timeout
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/f56ff8e5dbb21ebd.
Report an issue: GitHub.