hibernate/hibernate-orm · error · UnsupportedOperationException
Spanner does not support skip locked.
Error message
Spanner does not support skip locked.
What it means
SpannerDialect.getForUpdateSkipLockedString() throws UnsupportedOperationException because Cloud Spanner has no SKIP LOCKED locking mode — readers in a conflicting transaction get aborted rather than skipping rows. Hibernate requests this string when a pessimistic lock with the SKIP_LOCKED timeout is requested, and the dialect rejects it since it cannot be rendered. The alias variant behaves identically.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java:1284
@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) {
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." );
}
}View on GitHub (pinned to fad1729dce)
Solutions
- Replace SKIP LOCKED job claiming with a Spanner-appropriate pattern: UPDATE ... WHERE processed=false with a timestamp lease, or an interleaved claim table.
- Use optimistic locking (@Version) and retry on StaleObjectStateException/OptimisticLockException instead of skipping rows.
- Remove the -2 lock timeout setting (jakarta.persistence.lock.timeout=-2 in Spring properties) for Spanner profiles.
- Catch UnsupportedOperationException at the claim boundary and fall back to plain FOR UPDATE within a short transaction.
Example fix
// before (Spring Data JPA)
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints(@QueryHint(name = "jakarta.persistence.lock.timeout", value = "-2")) // SKIP LOCKED
List<Task> findNextTasks(...);
// after — lease-claim update instead of skip locked
@Modifying @Query("update Task t set t.leaseUntil = :until where t.id in :ids and t.leaseUntil < :now")
int leaseTasks(...); Defensive patterns
Strategy: validation
Validate before calling
boolean skipLocked = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED;
if (skipLocked && (dialect instanceof SpannerDialect || dialect instanceof SpannerPostgreSQLDialect)) {
throw new IllegalArgumentException("SKIP LOCKED unsupported on Spanner; use a lease-based claim query");
} Try / catch
try {
return query.list();
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("skip locked")) { /* fall back to lease-claim UPDATE */ }
throw e;
} Prevention
- Do not port PostgreSQL SKIP LOCKED queues to Spanner; use conditional UPDATE leases.
- Never set lock timeout -2 in Spanner JPA profiles.
- Use @Version optimistic locking for contended entities.
When it happens
Trigger: session.find()/lock() or Query.setLockOptions() with LockOptions.setTimeOut(LockOptions.SKIP_LOCKED) (i.e. Timeouts.SKIP_LOCKED_MILLI = -2), or explicit SKIP LOCKED emulation, on a connection using SpannerDialect.
Common situations: Queue/worklist processing ('select next N unlocked rows') written against PostgreSQL SKIP LOCKED and pointed at Spanner; scheduler or job-claiming code that uses -2 timeout constants; Spring @Lock(PESSIMISTIC_WRITE) with LockModeType properties requesting skip-locked via jakarta.persistence.lock.timeout=-2.
Related errors
- Spanner does not support no wait.
- Spanner does not support lock timeout.
- Spanner doesn't support for-update with skip locked timeout
- Spanner does not support skip locked.
- Spanner doesn't support for-update with no-wait timeout
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/bf83ccac968bc74c.
Report an issue: GitHub.