{"record":{"id":"c7dfe8d119ae7547","repo":"hibernate/hibernate-orm","slug":"connection-lock-timeout-does-not-accept-skip-locke-c7dfe8","errorCode":null,"errorMessage":"Connection lock-timeout does not accept skip-locked","messagePattern":"Connection lock-timeout does not accept skip-locked","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/TransactSQLLockingSupport.java","lineNumber":141,"sourceCode":"\t\t\t\t\t\treturn switch ( timeoutInMilliseconds ) {\n\t\t\t\t\t\t\tcase -1 -> Timeouts.WAIT_FOREVER;\n\t\t\t\t\t\t\tcase 0 -> Timeouts.NO_WAIT;\n\t\t\t\t\t\t\tdefault -> Timeout.milliseconds( timeoutInMilliseconds );\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t\tconnection,\n\t\t\t\t\tfactory\n\t\t\t);\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLockTimeout(Timeout timeout, Connection connection, SessionFactoryImplementor factory) {\n\t\t\tHelper.setLockTimeout(\n\t\t\t\t\ttimeout,\n\t\t\t\t\t(t) -> {\n\t\t\t\t\t\tfinal int milliseconds = timeout.milliseconds();\n\t\t\t\t\t\tif ( milliseconds == Timeouts.SKIP_LOCKED_MILLI ) {\n\t\t\t\t\t\t\tthrow new HibernateException( \"Connection lock-timeout does not accept skip-locked\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn milliseconds;\n\t\t\t\t\t},\n\t\t\t\t\t\"set lock_timeout %s\",\n\t\t\t\t\tconnection,\n\t\t\t\t\tfactory\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic static class SybaseImpl implements ConnectionLockTimeoutStrategy {\n\t\tpublic static final SybaseImpl IMPL = new SybaseImpl();\n\n\t\t@Override\n\t\tpublic Level getSupportedLevel() {\n\t\t\treturn Level.EXTENDED;\n\t\t}\n","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/TransactSQLLockingSupport.java#L123-L159","documentation":"On SQL Server, Hibernate applies pessimistic-lock timeouts with 'set lock_timeout N' (milliseconds) via TransactSQLLockingSupport.SQLServerImpl. SQL Server's connection lock_timeout is expressive enough for real waits and no-wait (0 ms, Level.EXTENDED), but SKIP_LOCKED (-2 ms) is purely a locking-clause concept with no session setting equivalent, so it is rejected with this HibernateException. Use 'FOR UPDATE SKIP LOCKED' / READPAST-style clause semantics instead.","triggerScenarios":"session.buildLockRequest(LockOptions.UPGRADE_SKIPLOCKED).lock(entity) / lockOptions.setTimeOut(-2); em.find(id, PESSIMISTIC_WRITE, hints) or locking queries with 'jakarta.persistence.lock.timeout' = -2 on SQL Server or Sybase dialects routed through the connection-timeout path (LockTimeoutHandler).","commonSituations":"Work-queue implementations using skip-locked semantics that set the timeout magic value instead of relying on the clause; global lock.timeout = -2 hints in persistence.xml; entity models/portable repos shared across SQL Server and PostgreSQL where the hint works differently; Hibernate version upgrades that moved timeout handling onto ConnectionLockTimeoutStrategy.","solutions":["Do not pass SKIP_LOCKED as a timeout; get skip-locked behavior from the locking clause (SQL Server 'FOR UPDATE SKIP LOCKED' equivalent / READPAST) or native SQL","Use a real positive timeout in ms or WAIT_FOREVER (-1) when the connection-level path applies","Guard with getConnectionLockTimeoutStrategy().getSupportedLevel() and reject/adjust magic values below Level.EXTENDED semantics","Remove -2 values from shared lock timeout configuration"],"exampleFix":"// before\nMap<String, Object> hints = Map.of(\"jakarta.persistence.lock.timeout\", -2); // SKIP_LOCKED -> throws\nList<Job> jobs = em.createQuery(...).setLockMode(LockModeType.PESSIMISTIC_WRITE).setHints(hints).getResultList();\n\n// after: plain short wait through 'set lock_timeout'\nMap<String, Object> hints = Map.of(\"jakarta.persistence.lock.timeout\", 1000);","handlingStrategy":"validation","validationCode":"int millis = lockOptions.getTimeOut();\nif (millis == Timeouts.SKIP_LOCKED_MILLI) {\n    lockOptions.setTimeOut(1000); // 'set lock_timeout' cannot express skip-locked on SQL Server\n}","typeGuard":"static boolean acceptsConnectionTimeout(ConnectionLockTimeoutStrategy s, int millis) {\n    if (s.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.NONE) return false;\n    return millis != Timeouts.SKIP_LOCKED_MILLI; // SQL Server is EXTENDED: no-wait (0) is fine\n}","tryCatchPattern":"try {\n    session.buildLockRequest(lockOptions).lock(entity);\n} catch (HibernateException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"does not accept skip-locked\")) {\n        lockOptions.setTimeout(1000);\n        session.buildLockRequest(lockOptions).lock(entity);\n    } else { throw e; }\n}","preventionTips":["On SQL Server, skip-locked belongs in the locking clause (FOR UPDATE SKIP LOCKED), never in set lock_timeout","No-wait works here: hint value 0 is accepted (Level.EXTENDED)","Avoid timeout magic values in shared locking utilities","Test locking behavior per database in CI"],"tags":["sql-server","pessimistic-locking","lock-timeout","skip-locked","hibernate"],"backgroundTag":"pessimistic-lock-timeout-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}