Skip to content
SQLite

SQLite: FOREIGN KEY constraint failed

FOREIGN KEY constraint failed (a child row has no parent, or a parent still has children)

Applies to: SQLite 3.6.19 and later (foreign key enforcement); examples run on 3.39.2, shell output from 3.50.6
Last technically reviewed 24 October 2026 on SQLite 3.39.2 (PHP PDO_SQLITE) and the sqlite3 shell 3.50.6
The full message
FOREIGN KEY constraint failed
Other forms of this message
sqlite3 shell (3.50.6), running a script
Runtime error near line 4: FOREIGN KEY constraint failed (19)
PHP PDO
SQLSTATE[23000]: Integrity constraint violation: 19 FOREIGN KEY constraint failed
Python sqlite3 (raised as sqlite3.IntegrityError)
sqlite3.IntegrityError: FOREIGN KEY constraint failed
Result code
SQLITE_CONSTRAINT (19); extended SQLITE_CONSTRAINT_FOREIGNKEY (787)
Product
SQLite library
Versions
SQLite 3.6.19 and later (foreign key enforcement); examples run on 3.39.2, shell output from 3.50.6
Last reviewed
24 October 2026

What it means

This error means a write would leave a child row pointing at a parent row that does not exist, so SQLite rejected it; the message does not say which table or key.

A foreign key (REFERENCES customers (id)) requires every non-NULL value in the child column to exist in the parent key. SQLite checks it on every INSERT and UPDATE of the child table and on every DELETE or key UPDATE of the parent. An immediate constraint fails the statement at once; a DEFERRABLE INITIALLY DEFERRED constraint is checked at COMMIT, and the COMMIT fails while violations remain (the transaction stays open, so you can fix the data or roll back). Unlike the other constraint messages, this one names no table or column: use PRAGMA foreign_key_list and PRAGMA foreign_key_check to find it.

Foreign keys are off by default in SQLite, and the setting belongs to the connection, not the database file: each connection must run PRAGMA foreign_keys = ON (outside a transaction, where it is silently ignored). That is why the same code can fail in one tool and succeed in another, and why a database can already contain orphan rows that were written while enforcement was off. With DROP TABLE on a parent, SQLite first performs an implicit DELETE, so dropping a referenced table fails with this error too. If the parent key itself is not a PRIMARY KEY or UNIQUE column, SQLite reports a different error, "foreign key mismatch", instead.

Common causes

  • A child row is inserted before its parent, or with a parent id that was mistyped, never created or belongs to another database.
  • A parent row is deleted (or its key changed) while child rows still reference it and the foreign key has no ON DELETE or ON UPDATE action.
  • DROP TABLE on a parent table that still has referencing rows.
  • A bulk load or migration inserts tables in the wrong order, or a deferred constraint is still violated when the transaction commits.

Diagnose it

Read-only These statements only read the schema (sqlite_schema and read-only PRAGMA queries) or your own data. They do not change data, settings or the database file, so they are safe to run first.

Is enforcement on in this connection?

PRAGMA foreign_keys;
What to look for

1 when foreign keys are enforced, 0 when they are not (the default). Run it from the same connection as the failing code, because each connection has its own setting.

Which foreign keys does the table have?

The error does not name the constraint, so list the foreign keys of the table you were writing to (or of the child tables, when you were deleting a parent).

PRAGMA foreign_key_list(orders);
What to look for

One row per key column: table is the parent, from the child column, to the parent column, plus the on_update and on_delete actions. NO ACTION means a delete of a referenced parent fails.

List every row that breaks a foreign key

foreign_key_check reads the whole database (or one table) and works even while enforcement is off, so it also finds orphans written earlier.

PRAGMA foreign_key_check;
PRAGMA foreign_key_check(orders);
What to look for

No rows when everything is consistent. Otherwise one row per violation: the child table, its rowid, the missing parent table and fkid (the id from foreign_key_list).

Find the child rows that reference a parent

Before deleting a parent, see what still points at it.

SELECT o.id, o.customer_id, o.total
FROM orders AS o
WHERE o.customer_id = 1;  -- the parent key you want to delete
What to look for

The rows that block the delete. Delete or reassign them first, or give the foreign key an ON DELETE action.

How to fix it

Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.

Insert the parent first (in one transaction)

Changes data

Create the parent row before the child, and wrap the pair in a transaction so a failure leaves neither behind. For a new parent, read its id back with last_insert_rowid() (or RETURNING on 3.35.0 and later) rather than guessing it.

BEGIN;
INSERT INTO customers (id, name) VALUES (99, 'Sara');
INSERT INTO orders (customer_id, total) VALUES (99, 10);
COMMIT;

Remove or reassign the children before deleting the parent

Changes data

Decide what should happen to the dependent rows: move them to another parent or delete them, in the same transaction as the parent delete.

Caution: Deleting child rows removes data permanently. Run the SELECT from the diagnostics first, check the count, and take a copy of the database file if the rows matter.

BEGIN;
DELETE FROM orders WHERE customer_id = 1;
DELETE FROM customers WHERE id = 1;
COMMIT;

Define what a parent delete should do (ON DELETE)

Changes schema

If deleting a customer should delete its orders (CASCADE) or keep them with no customer (SET NULL), declare that in the foreign key. SQLite cannot change a foreign key with ALTER TABLE, so this needs the table rebuild procedure; the definition of a new table looks like this.

Caution: CASCADE deletes child rows automatically and silently whenever a parent is deleted, including through INSERT OR REPLACE on the parent. Use it only where the children have no meaning without the parent.

CREATE TABLE order_notes (
    id       INTEGER PRIMARY KEY,
    order_id INTEGER NOT NULL REFERENCES orders (id) ON DELETE CASCADE,
    note     TEXT
);

Defer the check for loads in any order

Changes configuration

For a bulk load or circular references, PRAGMA defer_foreign_keys = ON inside a transaction postpones every foreign key check to COMMIT for that transaction only. The data must still be consistent when you commit, otherwise COMMIT fails and the transaction stays open.

BEGIN;
PRAGMA defer_foreign_keys = ON;
INSERT INTO orders (customer_id, total) VALUES (100, 25);
INSERT INTO customers (id, name) VALUES (100, 'Ali');
COMMIT;

Examples

Inserting an order for a customer that does not exist

PRAGMA foreign_keys = ON;

CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE orders (
    id          INTEGER PRIMARY KEY,
    customer_id INTEGER REFERENCES customers (id),
    total       REAL
);

INSERT INTO orders (customer_id, total) VALUES (99, 10);  -- no customer 99
Result
FOREIGN KEY constraint failed

Reproduced on SQLite 3.39.2, 24 October 2026.

Deleting a customer who still has orders

PRAGMA foreign_keys = ON;

CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER REFERENCES customers (id), total REAL);
INSERT INTO customers (id, name) VALUES (1, 'Sara');
INSERT INTO orders (customer_id, total) VALUES (1, 10);

DELETE FROM customers WHERE id = 1;
Result
FOREIGN KEY constraint failed

Reproduced on SQLite 3.39.2, 24 October 2026.

Dropping a parent table that is still referenced

PRAGMA foreign_keys = ON;

CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER REFERENCES customers (id), total REAL);
INSERT INTO customers (id, name) VALUES (1, 'Sara');
INSERT INTO orders (customer_id, total) VALUES (1, 10);

DROP TABLE customers;  -- runs an implicit DELETE first
Result
FOREIGN KEY constraint failed

Reproduced on SQLite 3.39.2, 24 October 2026.

A deferred foreign key fails at COMMIT

PRAGMA foreign_keys = ON;

CREATE TABLE orders (id INTEGER PRIMARY KEY, total REAL);
CREATE TABLE order_lines (
    id       INTEGER PRIMARY KEY,
    order_id INTEGER REFERENCES orders (id) DEFERRABLE INITIALLY DEFERRED
);

BEGIN;
INSERT INTO order_lines (order_id) VALUES (500);  -- accepted for now
COMMIT;  -- fails; the transaction is still open
ROLLBACK;
Result
FOREIGN KEY constraint failed

Reproduced on SQLite 3.39.2, 24 October 2026.

How to prevent it

Turn foreign keys on in every connection your application opens, right after connecting and before any transaction (most frameworks have a connection hook or option for this). Then run PRAGMA foreign_key_check once on existing databases: rows written while enforcement was off are not checked retroactively when you turn it on.

Write parents before children and delete children before parents, inside one transaction. Index the child key columns (for example CREATE INDEX ix_orders_customer ON orders (customer_id)), because every parent delete or key change has to search the child table. Do not switch foreign keys off to make an error go away: SQLite will not re-check the rows written meanwhile, and the orphans surface later as missing joins and wrong totals.

Common questions

How do I find which foreign key failed?

SQLite does not name it in the message. Run PRAGMA foreign_key_list on the table you wrote to see its keys, then query the parent for the value you used. For existing data, PRAGMA foreign_key_check lists every violating row with its table, rowid and parent table.

Why does the same insert work in one tool and fail in another?

Foreign key enforcement is a per-connection setting and is off by default. The connection that failed ran PRAGMA foreign_keys = ON (or was built with foreign keys enabled by default); the other did not. Check with PRAGMA foreign_keys in each.

I ran PRAGMA foreign_keys = ON but nothing changed. Why?

The pragma is ignored inside a transaction, without any error. Run it before BEGIN, then read it back with PRAGMA foreign_keys to confirm it returns 1.

Does a NULL in the child column fail the foreign key?

No. A child row whose foreign key column is NULL needs no parent. If every child must have a parent, declare the column NOT NULL as well.

Learn more on CodeWithSQL

Official documentation

Last technically reviewed 24 October 2026; examples and diagnostics run on SQLite 3.39.2 (PHP PDO_SQLITE) and the sqlite3 shell 3.50.6. Messages are the text the SQLite library itself returns (sqlite3_errmsg) for the versions shown.

Still stuck on a SQLite error?

Browse the full SQLite error library, or get hands-on help from an experienced SQL professional.