{"record":{"id":"968f27fffec0d159","repo":"hibernate/hibernate-orm","slug":"spanner-doesn-t-support-for-update-with-no-wait-ti","errorCode":null,"errorMessage":"Spanner doesn't support for-update with no-wait timeout","messagePattern":"Spanner doesn't support for-update with no-wait timeout","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/SpannerPostgreSQLDialect.java","lineNumber":500,"sourceCode":"\n\t@Override\n\tpublic String getReadLockString(Timeout timeout) {\n\t\treturn getWriteLockString( timeout.milliseconds() );\n\t}\n\n\t@Override\n\tpublic String getReadLockString(String aliases, Timeout timeout) {\n\t\treturn getWriteLockString( timeout.milliseconds() );\n\t}\n\n\t@Override\n\tpublic String getReadLockString(String aliases, int timeout) {\n\t\treturn getWriteLockString( timeout );\n\t}\n\n\t@Override\n\tpublic String getForUpdateNowaitString() {\n\t\tthrow new UnsupportedOperationException(\n\t\t\t\t\"Spanner doesn't support for-update with no-wait timeout\" );\n\t}\n\n\t@Override\n\tpublic String getForUpdateNowaitString(String aliases) {\n\t\treturn getForUpdateNowaitString();\n\t}\n\n\t@Override\n\tpublic String getForUpdateSkipLockedString() {\n\t\tthrow new UnsupportedOperationException(\n\t\t\t\t\"Spanner doesn't support for-update with skip locked timeout\" );\n\t}\n\n\t@Override\n\tpublic String getForUpdateSkipLockedString(String aliases) {\n\t\treturn getForUpdateSkipLockedString();\n\t}","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/SpannerPostgreSQLDialect.java#L482-L518","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n@Lock(LockModeType.PESSIMISTIC_WRITE)\n@QueryHints(@QueryHint(name = \"jakarta.persistence.lock.timeout\", value = \"0\")) // NO_WAIT encoding\nList<Order> lockedOrders();\n\n// after\n@Lock(LockModeType.PESSIMISTIC_WRITE) // no timeout hint\nList<Order> lockedOrders();","handlingStrategy":"validation","validationCode":"if (dialect instanceof SpannerPostgreSQLDialect && timeouts.isNoWait(timeout)) {\n  timeout = Timeouts.NO_TIMEOUT; // Spanner PG: plain FOR UPDATE only\n}","typeGuard":null,"tryCatchPattern":"try { return query.getResultList(); }\ncatch (UnsupportedOperationException e) {\n  if (e.getMessage().contains(\"no-wait\")) { /* strip timeout hint and re-run */ }\n  throw e;\n}","preventionTips":["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."],"tags":["hibernate","cloud-spanner","spanner-postgresql","locking","nowait","unsupportedoperationexception"],"backgroundTag":"nowait-not-supported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}