hibernate/hibernate-orm · error · IllegalArgumentException

Unexpected PostgreSQL lock_timeout format: {}

Error message

Unexpected PostgreSQL lock_timeout format: {}

What it means

PostgreSQLLockingSupport.getLockTimeout reads the baseline lock timeout by running 'show lock_timeout' and parsing the returned string. It understands '0' (wait forever) plus amounts with units ms, s, min, h, and d; any other unit or format falls through to IllegalArgumentException('Unexpected PostgreSQL lock_timeout format: ...'). PostgreSQL echoes the stored value including units, so a server or pool that configured lock_timeout in an unparsed unit (e.g. microseconds, shown as 'us') makes Hibernate's parser fail.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/PostgreSQLLockingSupport.java:104

					//   * Non-zero values may be returned with units such as:
					//       - milliseconds: "500ms"
					//       - seconds:      "3s"
					//       - minutes:      "1min"
					//       - hours:        "1h"
					// Therefore, we need to parse this String carefully to reconstruct the correct Timeout.
					String value = resultSet.getString( 1 );
					if ( "0".equals( value ) ) {
						return Timeouts.WAIT_FOREVER;
					}
					final var unitStartIndex = findUnitStartIndex( value );
					final var amount = Integer.parseInt( value, 0, unitStartIndex, 10 );
					return switch ( unitStartIndex == -1 ? "ms" : value.substring( unitStartIndex ) ) {
						case "ms" -> Timeout.milliseconds( amount );
						case "s" -> Timeout.seconds( amount );
						case "min" -> Timeout.seconds( amount * 60 );
						case "h" -> Timeout.seconds( amount * 3600 );
						case "d" -> Timeout.seconds( amount * 3600 * 24 );
						default -> throw new IllegalArgumentException(
							"Unexpected PostgreSQL lock_timeout format: " + value );
					};
				},
				connection,
				factory
		);
	}

	@Override
	public void setLockTimeout(Timeout timeout, Connection connection, SessionFactoryImplementor factory) {
		Helper.setLockTimeout(
				timeout,
				(t) -> {
					final int milliseconds = timeout.milliseconds();
					if ( milliseconds == SKIP_LOCKED_MILLI ) {
						throw new HibernateException( "Connection lock-timeout does not accept skip-locked" );
					}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Set lock_timeout using a unit Hibernate parses: run "set lock_timeout = '250ms'" (or s/min/h/d) in pool init SQL instead of microsecond values
  2. Check the current value with 'show lock_timeout' on the same connection and normalize it before issuing pessimistic locks
  3. If a pooler/proxy is in play, bypass it to confirm what the server actually returns for SHOW
  4. Upgrade Hibernate - parser coverage may grow; verify against your version's PostgreSQLLockingSupport

Example fix

# before (pool init or session sets a unit Hibernate does not parse)
set lock_timeout = '750us';

# after (standard unit)
set lock_timeout = '750ms';
Defensive patterns

Strategy: try-catch

Validate before calling

// normalize the setting to a unit Hibernate parses before locking
try (var st = connection.createStatement()) {
    st.execute("set lock_timeout = '250ms'");
}

Type guard

static boolean isParsablePgTimeout(String value) {
    if (value == null || value.isBlank()) return false;
    if (value.equals("0")) return true;
    var m = java.util.regex.Pattern.compile("^(\\d+)(ms|s|min|h|d)$").matcher(value);
    return m.matches();
}

Try / catch

try {
    session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(entity);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Unexpected PostgreSQL lock_timeout format")) {
        // reset to a standard unit on this connection, then retry
        // e.g. execute "set lock_timeout = '250ms'" and repeat the lock
    } else { throw e; }
}

Prevention

When it happens

Trigger: Someone or something ran "set lock_timeout = '1us'" (or any sub-millisecond/odd unit) on the connection or server so SHOW returns e.g. '1us', which finds no case in the unit switch; PostgreSQL-compatible engines or proxies returning nonstandard text for 'show lock_timeout'; any manual change of the server's lock_timeout GUC to a unit outside {ms, s, min, h, d} before a pessimistic lock triggers the baseline read in LockTimeoutHandler.performPreAction.

Common situations: Connection-pool connection-init SQL (HikariCP connectionInitSql) or a pooler (PgBouncer) setting lock_timeout with microsecond precision; ops tuning GUCs on RDS/Cloud SQL; PostgreSQL forks/shims that format settings differently than vanilla PG; a DBA script setting unusual units globally.

Understand the failure class

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/77cb8d24caeff9af. Report an issue: GitHub.