hibernate/hibernate-orm · error · UnsupportedOperationException
Spanner doesn't support for-update with no-wait timeout
Error message
Spanner doesn't support for-update with no-wait timeout
What it means
SpannerPostgreSQLDialect.getForUpdateNowaitString() throws UnsupportedOperationException('Spanner doesn't support for-update with no-wait timeout'). Even though this dialect speaks the PostgreSQL wire protocol (used by Google's Spanner PostgreSQL interface), Cloud Spanner itself has no NOWAIT lock mode, so the inherited PostgreSQL behavior is overridden to fail fast. Hibernate calls it when a pessimistic lock with NO_WAIT is rendered — including via the alias overload, which delegates here.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/SpannerPostgreSQLDialect.java:500
@Override
public String getReadLockString(Timeout timeout) {
return getWriteLockString( timeout.milliseconds() );
}
@Override
public String getReadLockString(String aliases, Timeout timeout) {
return getWriteLockString( timeout.milliseconds() );
}
@Override
public String getReadLockString(String aliases, int timeout) {
return getWriteLockString( timeout );
}
@Override
public String getForUpdateNowaitString() {
throw new UnsupportedOperationException(
"Spanner doesn't support for-update with no-wait timeout" );
}
@Override
public String getForUpdateNowaitString(String aliases) {
return getForUpdateNowaitString();
}
@Override
public String getForUpdateSkipLockedString() {
throw new UnsupportedOperationException(
"Spanner doesn't support for-update with skip locked timeout" );
}
@Override
public String getForUpdateSkipLockedString(String aliases) {
return getForUpdateSkipLockedString();
}View on GitHub (pinned to fad1729dce)
Solutions
- Remove NO_WAIT from lock options/hints; use plain FOR UPDATE, which the Spanner PG interface supports.
- Catch UnsupportedOperationException and fall back to default locking when it fires.
- Implement fail-fast via transaction-level timeouts rather than SQL lock suffixes.
- Keep the Spanner PG datasource in a separate JPA properties profile stripped of lock.timeout settings.
Example fix
// before @Lock(LockModeType.PESSIMISTIC_WRITE) @QueryHints(@QueryHint(name = "jakarta.persistence.lock.timeout", value = "0")) // NO_WAIT encoding List<Order> lockedOrders(); // after @Lock(LockModeType.PESSIMISTIC_WRITE) // no timeout hint List<Order> lockedOrders();
Defensive patterns
Strategy: validation
Validate before calling
if (dialect instanceof SpannerPostgreSQLDialect && timeouts.isNoWait(timeout)) {
timeout = Timeouts.NO_TIMEOUT; // Spanner PG: plain FOR UPDATE only
} Try / catch
try { return query.getResultList(); }
catch (UnsupportedOperationException e) {
if (e.getMessage().contains("no-wait")) { /* strip timeout hint and re-run */ }
throw e;
} Prevention
- Do not assume PostgreSQL locking parity on the Spanner PG interface.
- Remove lock.timeout hints from Spanner PG persistence units.
- Test fail-fast paths with transaction timeouts instead.
When it happens
Trigger: Using the Spanner PostgreSQL-dialect datasource and requesting LockOptions.NO_WAIT (Timeouts.NO_WAIT_MILLI) with PESSIMISTIC_WRITE/READ, e.g. query.setLockOptions(lo) where lo.setTimeOut(LockOptions.NO_WAIT); getForUpdateNowaitString(String) also funnels into this throw.
Common situations: Teams assuming 'PostgreSQL dialect = PostgreSQL locking' when moving an existing Spring Boot service to Cloud Spanner's PG interface; copied @QueryHints with lock.timeout sentinels; ShedLock/quartz-style routines that use NOWAIT.
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 doesn't support for-update with skip locked timeout
- Spanner does not support lock timeout.
- Spanner does not support skip locked.
- Spanner does not support no wait.
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/968f27fffec0d159.
Report an issue: GitHub.