Skip to content

55P03 — lock_not_available

Source-backed full entry for PostgreSQL SQLSTATE 55P03.

55P03

At a glance

55P03 reports that a requested lock could not be obtained under the operation’s selected wait policy. Fixed paths cover row locks, relation locks, LOCK TABLE, lock_timeout, and maintenance commands that skip work.

Field Value
SQLSTATE 55P03
Condition lock_not_available
Status active
Known present by 8.0.0
Locked snapshots 9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3
Macros ERRCODE_LOCK_NOT_AVAILABLE
Aliases

Meaning

Row-lock callers use LockWaitError and ConditionalXactLockTableWait()/ConditionalMultiXactIdWait() to fail immediately with could not obtain lock on row in relation "%s". Relation and LOCK TABLE callers use ConditionalLockRelationOid() and report a relation variant. A lock_timeout interrupt is another ERROR path, canceling statement due to lock timeout; it means the wait exceeded the configured timeout, not that NOWAIT was requested.

VACUUM and ANALYZE use the same SQLSTATE when they cannot acquire their relation lock, but their ereport(elevel) is deliberately non-ERROR: ordinary maintenance reports a WARNING, and an autovacuum verbose path can use LOG. The command skips that object and continues, so a warning is not an aborted transaction.

Diagnosis

Keep the complete primary message, severity, relation or row name, lock mode, and statement. Inspect pg_stat_activity, pg_locks, blocker PIDs, transaction age, and whether the statement used NOWAIT, lock_timeout, or a maintenance command. Do not turn a skipped VACUUM/ANALYZE warning into a failed DML diagnosis.

The accepted row-lock case used a separate blocker and an autocommit contender. In an explicit transaction, a lock ERROR leaves the session INERROR until ROLLBACK or ROLLBACK TO SAVEPOINT; the accepted autocommit contender remained IDLE after its failed statement.

Response

Coordinate or release the blocker, or choose a deliberate wait/timeout/skip policy. For an ERROR in an explicit transaction, roll back the whole transaction or to an existing savepoint before issuing more SQL; verify which work was committed before replaying. In autocommit, change the blocking or timeout condition first, then retry the statement with an idempotency rule. For a maintenance WARNING/LOG, record the skipped relation and run maintenance later; do not issue ROLLBACK for a command that did not abort the transaction.

Observed diagnostics

The selected registry created a blocker holding SELECT ... FOR UPDATE in an explicit transaction and an autocommit contender issuing FOR UPDATE NOWAIT. PostgreSQL 18.6 and 10.21 returned ERROR / 55P03 with could not obtain lock on row in relation "nowait_rows"; the contender stayed IDLE. After the blocker rolled back, the same contender updated marker to repaired and verified it.

Representative case

The SQL is a role-labelled registry excerpt. Setup is run once; blocker and contender must be separate sessions. It covers the row-lock NOWAIT branch only, not lock_timeout or the maintenance skip branches.

-- setup (one maintenance session)
CREATE TABLE nowait_rows(id integer PRIMARY KEY, marker text NOT NULL);
INSERT INTO nowait_rows VALUES (1, 'seed');

-- blocker session: keep this transaction open
BEGIN;
SELECT id FROM nowait_rows WHERE id = 1 FOR UPDATE;

-- contender session, autocommit on: this is the 55P03 operation
SELECT id FROM nowait_rows WHERE id = 1 FOR UPDATE NOWAIT;

-- blocker session
ROLLBACK;

-- contender session after the blocker is released
UPDATE nowait_rows SET marker = 'repaired' WHERE id = 1 RETURNING marker;
SELECT marker FROM nowait_rows WHERE id = 1;

The passed case confirms this row-lock mechanism, its ERROR/IDLE boundary, and its repair step only; it does not prove that every lock mode or maintenance command has the same severity.

Versions

The locked catalogue records this condition from 8.0.0; fixed source coverage is PostgreSQL 18.6. The accepted runtime was observed on PostgreSQL 18.6 and 10.21.

55P02, 40001, 57014

Sources

src/backend/access/heap/heapam.c#L5178-5210

src/backend/catalog/namespace.c#L585-610

src/backend/tcop/postgres.c#L3420-3444

src/backend/commands/lockcmds.c#L130-145

src/backend/commands/vacuum.c#L835-880

The structured evidence record records fixed message roles, maintenance severity, and accepted runtime artifacts.