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
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

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.