hibernate/hibernate-orm · error · UnsupportedOperationException
Spanner does not support skip locked.
Error message
Spanner does not support skip locked.
What it means
This is the SKIP_LOCKED branch of SpannerPostgreSQLDialect.validateSpannerLockTimeout(): millis == Timeouts.SKIP_LOCKED_MILLI throws UnsupportedOperationException('Spanner does not support skip locked.'). It is invoked from getLockingClauseStrategy() whenever a query with lock options is translated, so a skip-locked request fails before SQL generation. Spanner's transaction model aborts conflicting accessors rather than skipping rows, hence the hard rejection.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/dialect/SpannerPostgreSQLDialect.java:535
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 );
}
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 void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
final var configurationService = serviceRegistry.requireService( ConfigurationService.class );
this.useIntegerForPrimaryKey = configurationService.getSetting(
USE_INTEGER_FOR_PRIMARY_KEY,
StandardConverters.BOOLEAN,
false
);
View on GitHub (pinned to fad1729dce)
Solutions
- Remove the -2 timeout hint and port the claim logic to a lease-based conditional UPDATE, the supported pattern on Spanner.
- Use optimistic locking + retry instead of skip-locked semantics.
- Catch UnsupportedOperationException in dialect-agnostic code paths and fall back to plain FOR UPDATE.
- Profile-separate JPA lock properties so Spanner never receives SKIP_LOCKED.
Example fix
// before
Query q = session.createQuery("from Task t where t.status = 'OPEN'", Task.class);
q.getLockOptions().setTimeOut(LockOptions.SKIP_LOCKED); // -2
// after
Query q = session.createQuery("from Task t where t.status = 'OPEN' and t.leaseUntil < :now", Task.class); Defensive patterns
Strategy: validation
Validate before calling
if (lockOptions.getTimeOut() == Timeouts.SKIP_LOCKED_MILLI && dialect instanceof SpannerPostgreSQLDialect) {
lockOptions.setTimeOut(LockOptions.NO_TIMEOUT);
} Try / catch
try { return query.getResultList(); }
catch (UnsupportedOperationException e) {
if (e.getMessage().contains("skip locked")) { /* lease-claim fallback */ }
throw e;
} Prevention
- Strip -2 lock timeouts from Spanner PG configurations.
- Implement row claiming with conditional UPDATEs.
- Run dialect-specific lock test suites.
When it happens
Trigger: On the Spanner PostgreSQL dialect: lock timeout -2 (LockOptions.SKIP_LOCKED or jakarta.persistence.lock.timeout=-2) attached to a query/finder with pessimistic locking; getLockingClauseStrategy reads lockOptions.getTimeOut(), hits the sentinel and throws.
Common situations: PG-native queue processors (SKIP LOCKED worklists) pointed at Spanner's PG interface; Spring properties copied between environments; integration test suites asserting lock behaviors that pass on PostgreSQL CI and fail on Spanner stages.
Related errors
- 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
- 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/f15bb4753af32c1b.
Report an issue: GitHub.