{"record":{"id":"72d1b2869d00ef11","repo":"hibernate/hibernate-orm","slug":"connection-lock-timeout-does-not-accept-no-wait-72d1b2","errorCode":null,"errorMessage":"Connection lock-timeout does not accept no-wait","messagePattern":"Connection lock-timeout does not accept no-wait","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/CockroachLockingSupport.java","lineNumber":110,"sourceCode":"\t\t\t\tconnection,\n\t\t\t\tfactory\n\t\t);\n\t}\n\n\t@Override\n\tpublic void setLockTimeout(\n\t\t\tTimeout timeout,\n\t\t\tConnection connection,\n\t\t\tSessionFactoryImplementor factory) {\n\t\tHelper.setLockTimeout(\n\t\t\t\ttimeout,\n\t\t\t\t(t) -> {\n\t\t\t\t\tfinal int milliseconds = timeout.milliseconds();\n\t\t\t\t\tif ( milliseconds == SKIP_LOCKED_MILLI ) {\n\t\t\t\t\t\tthrow new HibernateException( \"Connection lock-timeout does not accept skip-locked\" );\n\t\t\t\t\t}\n\t\t\t\t\tif ( milliseconds == NO_WAIT_MILLI ) {\n\t\t\t\t\t\tthrow new HibernateException( \"Connection lock-timeout does not accept no-wait\" );\n\t\t\t\t\t}\n\t\t\t\t\treturn milliseconds == WAIT_FOREVER_MILLI ? 0 : milliseconds;\n\t\t\t\t},\n\t\t\t\t\"set lock_timeout = %s\",\n\t\t\t\tconnection,\n\t\t\t\tfactory\n\t\t);\n\t}\n\n}\n","sourceCodeStart":92,"sourceCodeEnd":121,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/CockroachLockingSupport.java#L92-L121","documentation":"Hibernate 7 applies pessimistic-lock timeouts on CockroachDB via the JDBC connection setting 'set lock_timeout = N' (CockroachLockingSupport.setLockTimeout -> Helper.setLockTimeout). The value strategy maps WAIT_FOREVER (-1 ms) to 0, so a timeout of 0 ms (Timeouts.NO_WAIT_MILLI, the JPA no-wait magic value) cannot be distinguished from wait-forever and is rejected with this HibernateException. The support level is SUPPORTED, not EXTENDED, so no-wait is never accepted on this path.","triggerScenarios":"session.buildLockRequest(LockOptions.UPGRADE_NOWAIT).lock(entity) or lockOptions.setTimeOut(0); em.find(id, PESSIMISTIC_WRITE, hints) with 'jakarta.persistence.lock.timeout'=0 (or legacy javax prefix); Timeouts.NO_WAIT reaching setLockTimeout when the dialect routes lock timeouts through the connection (LockTimeoutType.CONNECTION).","commonSituations":"Copy-pasted 'fail fast' locking code that uses the JPA hint value 0 for no-wait; a global lock.timeout=0 property in persistence.xml; switching an application from SQL Server (where no-wait works, Level.EXTENDED) to CockroachDB; Hibernate 6 to 7 migrations where lock timeout handling moved to ConnectionLockTimeoutStrategy.","solutions":["Use the smallest real timeout CockroachDB accepts (e.g. 1-50 ms) to approximate no-wait, or WAIT_FOREVER (-1) to wait indefinitely","If you need true no-wait, use a locking clause variant supported by the database (native 'FOR UPDATE NOWAIT') instead of the connection-level timeout","Check dialect.getLockingSupport().getConnectionLockTimeoutStrategy().getSupportedLevel(): only Level.EXTENDED (SQL Server/Sybase) accepts no-wait","Remove global 'jakarta.persistence.lock.timeout' = 0 settings that apply to every pessimistic lock"],"exampleFix":"// before\nMap<String, Object> hints = Map.of(\"jakarta.persistence.lock.timeout\", 0); // NO_WAIT -> throws\nem.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE, hints);\n\n// after: short real wait approximating no-wait on CockroachDB\nMap<String, Object> hints = Map.of(\"jakarta.persistence.lock.timeout\", 50);\nem.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE, hints);","handlingStrategy":"validation","validationCode":"int millis = lockOptions.getTimeOut();\nConnectionLockTimeoutStrategy.Level level = sessionFactory.getJdbcServices().getDialect()\n        .getLockingSupport().getConnectionLockTimeoutStrategy().getSupportedLevel();\nif (millis == Timeouts.NO_WAIT_MILLI && level != ConnectionLockTimeoutStrategy.Level.EXTENDED) {\n    lockOptions.setTimeOut(50); // 0 (no-wait) only works on EXTENDED dialects (SQL Server/Sybase)\n}","typeGuard":"static boolean acceptsConnectionTimeout(ConnectionLockTimeoutStrategy s, int millis) {\n    if (s.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.NONE) return false;\n    if (millis == Timeouts.SKIP_LOCKED_MILLI) return false;\n    return millis != Timeouts.NO_WAIT_MILLI\n            || s.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.EXTENDED;\n}","tryCatchPattern":"try {\n    em.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE, hints);\n} catch (HibernateException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"does not accept no-wait\")) {\n        hints = Map.of(\"jakarta.persistence.lock.timeout\", 50); // retry with a real timeout\n    } else { throw e; }\n}","preventionTips":["Do not use the JPA hint value 0 as a portable no-wait; only SQL Server/Sybase (Level.EXTENDED) accept it at connection level","Approximate no-wait with a small positive timeout plus PessimisticLockException handling","Audit persistence.xml and repository hints for lock.timeout = 0 or -2","Test lock scenarios against every production database"],"tags":["cockroachdb","pessimistic-locking","lock-timeout","no-wait","hibernate"],"backgroundTag":"pessimistic-lock-timeout-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}