hibernate/hibernate-orm · error · UnsupportedOperationException
Spanner does not support no wait.
Error message
Spanner does not support no wait.
What it means
SpannerDialect.getForUpdateNowaitString() throws UnsupportedOperationException because Cloud Spanner's locking (via its FOR UPDATE support) has no NOWAIT mode — lock waits are governed by the transaction, not a SQL suffix. Hibernate calls this method when a pessimistic lock with a no-wait timeout is requested (LockOptions.NO_WAIT), so the request can never be satisfied on Spanner. Companion overloads for aliases and skip-locked throw likewise.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java:1274
@Override
public String getWriteLockString(Timeout timeout) {
return getWriteLockString( timeout.milliseconds() );
}
@Override
public String getReadLockString(int timeout) {
validateSpannerLockTimeout( timeout );
return getForUpdateString();
}
@Override
public String getReadLockString(Timeout timeout) {
return getReadLockString( timeout.milliseconds() );
}
@Override
public String getForUpdateNowaitString() {
throw new UnsupportedOperationException( "Spanner does not support no wait." );
}
@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) {View on GitHub (pinned to fad1729dce)
Solutions
- Remove the NOWAIT option: use plain LockOptions.NONE timeout (0 milliseconds semantics per Timeouts) so getReadLockString()/getForUpdateString() paths are used, which Spanner supports.
- Catch UnsupportedOperationException around the locking call and retry with an ordinary FOR UPDATE, or accept wait semantics.
- If fail-fast behavior is required, implement it at the application level (e.g. transaction timeout or a lock table) rather than the SQL suffix.
- Verify the dialect in use — SpannerPostgreSQLDialect has the same restriction, so switching PG-dialect code to Spanner PG does not help.
Example fix
// before LockOptions lo = new LockOptions(LockMode.PESSIMISTIC_WRITE); lo.setTimeOut(LockOptions.NO_WAIT); // -> getForUpdateNowaitString() throws session.find(Order.class, id, lo); // after LockOptions lo = new LockOptions(LockMode.PESSIMISTIC_WRITE); // leave timeout unset/none — plain FOR UPDATE is supported session.find(Order.class, id, lo);
Defensive patterns
Strategy: validation
Validate before calling
boolean spanner = dialect instanceof SpannerDialect || dialect instanceof SpannerPostgreSQLDialect;
if (spanner && (lockOptions.getTimeOut() == LockOptions.NO_WAIT || Timeouts.isNoWaitTimeout(lockOptions.getTimeOut()))) {
lockOptions.setTimeOut(LockOptions.NO_TIMEOUT); // degrade to plain FOR UPDATE
} Try / catch
try {
return session.find(Order.class, id, lockOptions);
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("no wait")) {
LockOptions plain = new LockOptions(lockOptions.getLockMode());
return session.find(Order.class, id, plain);
}
throw e;
} Prevention
- Never set NO_WAIT lock timeouts on Spanner datasources.
- Keep lock configuration in per-dialect profiles.
- Prefer optimistic locking unless strict read consistency is required.
When it happens
Trigger: Calling session.lock()/find(id, lockOptions) or setting Query.setLockOptions() with LockOptions.NO_WAIT (timeout = 0 meaning nowait, i.e. Timeouts.NO_WAIT_MILLI) or PESSIMISTIC_WRITE combined with `setTimeOut(LockOptions.NO_WAIT)` while connected through SpannerDialect; also `select ... for update nowait` emulation attempts.
Common situations: Reusing pessimistic-locking code written for PostgreSQL/Oracle (where NOWAIT avoids long waits) against a Spanner deployment; default timeout constants copied into LockOptions; frameworks (e.g. ShedLock-style routines) that request NOWAIT to detect contention.
Related errors
- 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
- Spanner does not support lock timeout.
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/e44d9559edf44bcd.
Report an issue: GitHub.