Foreign key constraint fails
You tried to insert or update a row that points at a parent row which doesn't exist, or delete a parent row something still references. Plus the one thing every SQLite user eventually gets caught by — it isn't enforced unless you turn it on.
- MySQL:
Cannot add or update a child row: a foreign key constraint fails (...) - PostgreSQL:
ERROR: insert or update on table "orders" violates foreign key constraint "orders_customer_id_fkey" DETAIL: Key (customer_id)=(99) is not present in table "customers". - SQL Server:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_orders_customers". The conflict occurred in database "...", table "dbo.customers", column 'customer_id'. - SQLite:
FOREIGN KEY constraint failed
A scratch schema with the constraint actually declared, since the shared seed tables on this site don't have one:
Loading editor…
The two directions this happens
Inserting or updating a child row that points at a parent that doesn't
exist — the case above. The fix is almost always upstream: whatever
created customer_id = 99 on the order either has a bug, or is running
before the customer row it depends on has been committed (a common one in
batch loads and multi-step application logic — insert parents first).
Deleting a parent row something still references — same constraint,
the other direction. scratch_orders has a real row pointing at customer
1 from the block above, so deleting that customer is blocked too:
Loading editor…
If the delete is intentional, you generally have three honest options, declared on the constraint itself rather than worked around in every query that might delete a parent:
ON DELETE CASCADE— delete the children too.ON DELETE SET NULL— orphan the children (nullify the foreign key column, which has to be nullable).ON DELETE RESTRICT(the default behavior above) — refuse, which is usually right unless you've deliberately decided otherwise.
The SQLite-specific trap: it's off by default
This is the one genuinely SQLite-specific gotcha on this page, and it surprises people from the opposite direction of every other error here — instead of erroring too eagerly, SQLite doesn't enforce foreign keys at all unless you turn it on for the connection — explicitly turning it back off here so this block is honest about the default, regardless of what ran earlier on this page:
Loading editor…
That inserted an order pointing at a customer that doesn't exist, with no
error — the exact FOREIGN KEY REFERENCES clause that would stop this in
every other engine did nothing, because SQLite requires PRAGMA foreign_keys = ON to be set on every connection, every time — it's
not a one-time schema setting, and most application frameworks and
drivers don't turn it on for you. If you're relying on SQLite's foreign
keys to catch bad data during development, verify the pragma is actually
being set before trusting a clean run.
- Duplicate key / unique constraint violation — the other extremely common constraint error.
- DELETE — deleting rows that other tables may reference.
- INSERT — getting insert order right across related tables.
ON DELETE CASCADE to the foreign key above and rerun the delete to see the difference.Open the playground →