PostgreSQL error 55P03 (Lock Not Available) explained: what it means, why it happens, and how to fix it — with copy-paste code examples.
Catch the error and either retry after a short wait or skip the row. If that does not apply, drop NOWAIT and use FOR UPDATE with a lock_timeout instead — the full checklist is below.
SQLSTATE: 55P03
Official name: Lock Not Available
Service: PostgreSQL
A lock requested with the NOWAIT option could not be acquired immediately and the statement was aborted.
SELECT id FROM jobs WHERE status='pending'
ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
SKIP LOCKED skips rows already locked, returning only available work — ideal for concurrent workers without triggering 55P03.
Use with_for_update(nowait=False, skip_locked=True) on a query to avoid 55P03.
row = session.query(Task).filter_by(status='pending')\
.with_for_update(skip_locked=True).first()
Use an RPC that performs SELECT ... FOR UPDATE SKIP LOCKED for queue-style claims.
CREATE FUNCTION claim_task() RETURNS void AS $$
UPDATE tasks SET status='running'
WHERE id IN (SELECT id FROM tasks WHERE status='pending' FOR UPDATE SKIP LOCKED LIMIT 1)
$$ LANGUAGE sql;
Most often this happens when sELECT ... FOR UPDATE NOWAIT hits a row already locked by another transaction, or when lOCK TABLE ... NOWAIT on a table with an active conflicting lock.
Catch the error and either retry after a short wait or skip the row.
This page documents fixes for: sqlalchemy, supabase.
Recommendations are editorial — DB Error Reference takes no payment or affiliate fees for tool listings.
This page is based on the official PostgreSQL documentation linked below and adds practical troubleshooting guidance on top.