PostgreSQL Error 23503: Foreign Key Violation

PostgreSQL error 23503 (Foreign Key Violation) explained: what it means, why it happens, and how to fix it — with copy-paste code examples.

SQLSTATE 23503 PostgreSQL Last verified 2026-08-19

Quick Answer

Read the error detail for the constraint name and the offending key value. If that does not apply, verify the referenced parent row exists before inserting the child — the full checklist is below.

Error Code

SQLSTATE: 23503
Official name: Foreign Key Violation
System name: foreign_key_violation
Service: PostgreSQL

What does this error mean?

A foreign key constraint was violated because a referenced row does not exist, or an operation would orphan a referenced row.

Common Causes

How to Fix

  1. Read the error detail for the constraint name and the offending key value
  2. Verify the referenced parent row exists before inserting the child
  3. Either insert the parent first, or relax the constraint with ON DELETE SET NULL/ CASCADE
  4. Use DEFERRABLE INITIALLY DEFERRED to defer FK checks to commit time for multi-step imports
  5. Query pg_constraint to confirm the FK definition and referenced columns

Example Scenario

With orders(user_id) REFERENCES users(id), the app inserts an order for user_id = 42 from a request that carried a stale client-side value. PostgreSQL rejects it with SQLSTATE 23503: insert or update on table "orders" violates foreign key constraint "orders_user_id_fkey" — the users row with id 42 does not exist (deleted, never committed, or the value came from a different environment).

Diagnostic Commands

Run these to confirm the cause before applying a fix — each command answers a specific question.

Does the referenced parent row exist? sql
SELECT id FROM users WHERE id = 42;

No row = the classic 23503 on insert; confirm whether the parent was deleted or the id is simply wrong.

Which child rows would break on parent delete? sql
SELECT count(*) FROM orders WHERE user_id = 42;

A non-zero count explains a 23503 raised during DELETE of the parent (RESTRICT / NO ACTION).

Decision Guide

Error on INSERT/UPDATE of the child?
├─ parent missing → insert the parent first (or fix the id you send)
│    └─ within a transaction: order the statements so the parent commits first,
│       or make the FK DEFERRABLE INITIALLY DEFERRED
└─ parent exists → check you are hitting the right database/environment

Error on DELETE of the parent?
├─ children should go too → ON DELETE CASCADE
├─ children should detach → ON DELETE SET NULL
└─ neither → delete or archive the child rows first

Code Examples

Inspect a foreign key constraint sql
SELECT conname, conrelid::regclass AS table_name,
       pg_get_constraintdef(oid) AS definition
FROM pg_constraint
WHERE contype = 'f';

List all FK constraints and their exact definitions so you can see which columns and ON DELETE actions are in play.

Make a FK deferrable sql
ALTER TABLE orders
  ADD CONSTRAINT orders_customer_id_fkey
  FOREIGN KEY (customer_id) REFERENCES customers(id)
  DEFERRABLE INITIALLY DEFERRED;

Deferrable constraints are checked at commit, allowing you to insert child rows before parents within a transaction.

Framework-Specific Fixes

django

Create parent objects before children, or use bulk_create with explicit ordering; wrap in a transaction.

with transaction.atomic():
    parent = Parent.objects.create(name='x')
    Child.objects.create(parent=parent)

sqlalchemy

Flush parent rows before children so ORM assigns generated FK ids before the child insert fires.

parent = Parent(name='x')
session.add(parent)
session.flush()  # assigns parent.id
session.add(Child(parent_id=parent.id))

supabase

Insert parent records first via the dashboard or API, then reference their id in the child insert.

const { data: parent } = await supabase
  .from('parents').insert({ name: 'x' }).select().single();
await supabase.from('children').insert({ parent_id: parent.id });

You Might Also Like

Frequently Asked Questions

Why am I seeing PostgreSQL error 23503?

Most often this happens when inserting a child row whose parent id does not exist, or when deleting or updating a parent row that is still referenced by child rows without ON DELETE/UPDATE CASCADE.

How do I fix PostgreSQL error 23503?

Read the error detail for the constraint name and the offending key value.

Which frameworks have documented fixes for error 23503?

This page documents fixes for: django, sqlalchemy, supabase.

Official Sources

This page is based on the official PostgreSQL documentation linked below and adds practical troubleshooting guidance on top.