hibernate/hibernate-orm · error · UnsupportedOperationException
Spanner doesn't support for-update with skip locked timeout
Error message
Spanner doesn't support for-update with skip locked timeout
What it means
SpannerPostgreSQLDialect.getForUpdateSkipLockedString() throws UnsupportedOperationException('Spanner doesn't support for-update with skip locked timeout'). The Spanner PostgreSQL interface accepts PostgreSQL syntax broadly, but SKIP LOCKED semantics (skipping rows held by other transactions) do not exist in Spanner's transaction model, so the dialect blocks the request at SQL rendering. The alias overload delegates to this method and throws identically.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/SpannerPostgreSQLDialect.java:511
@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();
}
@Override
public LockingClauseStrategy getLockingClauseStrategy(
QuerySpec querySpec, LockOptions lockOptions) {
if ( lockOptions == null ) {
return NON_CLAUSE_STRATEGY;
}
validateSpannerLockTimeout( lockOptions.getTimeOut() );
return super.getLockingClauseStrategy( querySpec, lockOptions );
}
View on GitHub (pinned to fad1729dce)
Solutions
- Remove the SKIP_LOCKED timeout hint/option on the Spanner PG profile and redesign claim logic as a conditional UPDATE with a lease timestamp.
- Use optimistic @Version locking with retry for contended entities.
- Catch UnsupportedOperationException at the claim site and degrade to plain FOR UPDATE.
- Isolate queue/claim queries in dialect-aware repository variants so the PG-modeled one is never executed against Spanner.
Example fix
// before (PostgreSQL-style, throws on Spanner PG)
@QueryHints(@QueryHint(name = "jakarta.persistence.lock.timeout", value = "-2"))
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Task> findOpenTasks(Pageable p);
// after — lease-based claim
@Modifying @Query("update Task t set t.leaseUntil = :until where t.status = 'OPEN' and (t.leaseUntil is null or t.leaseUntil < :now)")
int claimTasks(Instant now, Instant until); Defensive patterns
Strategy: validation
Validate before calling
if (dialect instanceof SpannerPostgreSQLDialect && lockOptions.getTimeOut() == Timeouts.SKIP_LOCKED_MILLI) {
throw new IllegalArgumentException("SKIP LOCKED unsupported on Spanner PG; use lease-based claiming");
} Try / catch
try { return query.getResultList(); }
catch (UnsupportedOperationException e) {
if (e.getMessage().contains("skip locked")) { /* run lease UPDATE claim instead */ }
throw e;
} Prevention
- Port queue logic off SKIP LOCKED before moving to Spanner PG.
- Audit Spring @QueryHints for -2 values.
- Use optimistic locking for contention.
When it happens
Trigger: On the Spanner PG interface: Query.setLockOptions()/setLockMode() with timeout -2 (LockOptions.SKIP_LOCKED / Timeouts.SKIP_LOCKED_MILLI), or Spring hints jakarta.persistence.lock.timeout=-2 with pessimistic locks; also getForUpdateSkipLockedString(aliases) delegations.
Common situations: Lifting a PostgreSQL job-queue implementation (SELECT ... FOR UPDATE SKIP LOCKED) onto Spanner PG with minimal code changes; generic locking aspects applied to all datasources; tests that exercise all LockOptions constants across profiles.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Spanner does not support skip locked.
- Spanner does not support skip locked.
- Spanner doesn't support for-update with no-wait timeout
- Spanner does not support lock timeout.
- Spanner does not support no wait.
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/3697563e9b47283f.
Report an issue: GitHub.