SQLSTATE 23503Severity lowLab verified

Incident brief

Insert or update violates foreign key constraint

A row referenced a value in another table through a FOREIGN KEY, but that value doesn't exist there. PostgreSQL rejects the row to keep the two tables consistent.

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

In 10 seconds

What
Insert or update violates foreign key constraint
What triggers it
Create a parent table and a child table with a FOREIGN KEY referencing the parent.
The fix
Insert the parent row first, then the child row that references it.
Proof
Reproduced on PostgreSQL 16.14 → The INSERT referencing a non-existent parent id (999) was rejected with SQLSTATE 23503 and the row was never stored.

The fix

What to do right now

The immediate, application-level response to this error.

  • Insert the parent row first, then the child row that references it.
  • Double-check the referenced id actually exists before inserting.
  • Decide an ON DELETE policy (CASCADE, RESTRICT, SET NULL) up front so parent deletes behave the way you expect.
Fix — SQL
CREATE TABLE shop.orders (id integer primary key);
CREATE TABLE shop.order_items (
  id integer primary key,
  order_id integer REFERENCES shop.orders(id)
);

-- insert the parent first
INSERT INTO shop.orders (id) VALUES (1);
-- now the child insert has a matching parent row
INSERT INTO shop.order_items (id, order_id) VALUES (1, 1);

Related & next steps

Follow the thread

Everything this error touches — jump straight to the sibling error, term, runbook, or parameter.

Verification

PG 16.14
Last verified
2026-07-15 (Docker lab, PostgreSQL 16.14)
Reviewed by
Verified against PostgreSQL 16.14 in an isolated lab environment
Audit status
reviewed