SQLSTATE 55P03Severity mediumLab verified

Incident brief

Could not obtain lock on row

A session asked to lock a row with NOWAIT, but another session already had that row locked. Instead of waiting, PostgreSQL said no right away. The same SQLSTATE is also raised when lock_timeout expires while waiting for a row lock.

What lands in your log

ERROR: could not obtain lock on row in relation "orders"

Reproduced on PostgreSQL 16.14Verified 2026-08-15 (Docker lab, PostgreSQL 16.14)Verified against PostgreSQL 16.14 in an isolated lab environment

In 10 seconds

What triggers it
Create a table and insert one row.
Fix
Catch SQLSTATE 55P03 and retry or tell the user to try again in a moment.
Proof
Reproduced on PostgreSQL 16.14 → Session B was rejected the instant it asked for the lock, it never waited at all. Session A's own update went through normally once it committed.

Fix

What to do right now

Application-level steps for this error.

  • Catch SQLSTATE 55P03 and retry or tell the user to try again in a moment.
  • Use NOWAIT when the app should fail fast instead of sitting blocked.
  • Prefer lock_timeout for a short, bounded wait when a brief pause is acceptable.
  • For job queues, prefer FOR UPDATE SKIP LOCKED so workers skip busy rows without erroring.
Fix SQL
-- Fail-fast (NOWAIT): app catches 55P03 and retries / tells the user to wait
SELECT id, status FROM fulfillment.orders WHERE id = 1 FOR UPDATE NOWAIT;

-- Bounded wait (often better than infinite block OR instant fail):
SET lock_timeout = '2s';
SELECT id, status FROM fulfillment.orders WHERE id = 1 FOR UPDATE;
-- both NOWAIT and lock_timeout raise SQLSTATE 55P03 when the lock is not obtained
-- SKIP LOCKED is the other common pattern for worker queues (no error; skips busy rows)

Connected

Everything this error touches

Every page this SQLSTATE connects to: the concept that explains it, the runbooks that fix it, the parameters you tune to prevent it, and the sibling errors it travels with. All real cross-references. Jump straight in, or open the full interactive map.

Open in the interactive map →

Verification

PG 16.14
Last verified
2026-08-15 (Docker lab, PostgreSQL 16.14)
Verification scope
Verified against PostgreSQL 16.14 in an isolated lab environment
Audit status
reviewed
ShareLinkedInX

Went further?

Pro unlocks the second lab proof

Free page stops the bleeding. Pro adds the operational test, SQLSTATE audit, and deeper evidence, same error, more certainty.

FollowSubstackLinkedInnew errors · lab notes · hiring loops