“NOT NULL Constraint Failed” — Fix This SQL Error
A required column got no value. Supply one, give the column a default, or let it be null.
- DuckDB
-
Constraint Error: NOT NULL constraint failed: order_imports.customer_email - PostgreSQL
-
ERROR: null value in column "customer_email" of relation "order_imports" violates not-null constraint - MySQL
-
Column 'customer_email' cannot be null - SQL Server
-
Cannot insert the value NULL into column 'customer_email'; column does not allow nulls. INSERT fails. - SQLite
-
NOT NULL constraint failed: order_imports.customer_email
The symptom
An INSERT or UPDATE is rejected because a column
declared NOT NULL would end up empty. The whole statement
fails; it does not insert the other columns and leave that one blank.
The garden_shop practice tables load straight from CSV and
carry no constraints of their own, so the bench below declares a small table
with a NOT NULL rule to fail against.
DuckDB names the exact column:
Constraint Error: NOT NULL constraint failed:
order_imports.customer_email. That is the most useful part of the message. You do not have to guess
which column was empty, and on a wide insert that saves real time.
Three ways a value goes missing
The obvious one is an explicit null. The second is easier to
miss: leaving a column out of the column list means it takes its default,
and a column with no default defaults to null. Neither
statement below contains a value you would call wrong.
create or replace table order_imports (
order_id integer,
customer_email varchar not null
);
insert into order_imports values (1, null); -- customer_email is never named, so it defaults to null
insert into order_imports (order_id)
values (2);
The third is a source column that is null in more rows than you expected.
orders.coupon_code is populated on 6 of Garden Shop's 24
orders, so selecting it into a NOT NULL column fails on the
first null it reaches. A LEFT JOIN that finds no match does the
same thing for the same reason, though Garden Shop happens to have no
orphaned rows to demonstrate it with.
insert into order_imports
select order_id, coupon_code
from orders; Count the offending rows first
Before changing anything, count what would fail. "18 rows of 24" is a data problem to think about. "Every row" usually means the wrong column or the wrong join.
select count(*) as total_rows,
count(*) - count(coupon_code) as rows_without_coupon
from orders Pick the right fix
create or replace table order_imports (
order_id integer,
customer_email varchar not null
);
insert into order_imports values (1, null);
Running it raises
NOT NULL constraint failed: order_imports.customer_email.
create or replace table order_imports (
order_id integer,
customer_email varchar not null
);
insert into order_imports values (1, 'ada@example.com');
There are three, and they are not interchangeable. Supply the value when the
data exists somewhere. Give the column a DEFAULT when a
sensible placeholder exists and the rule should stay. Drop the
NOT NULL rule only when the column is genuinely optional, which
is a decision about the model rather than about this one insert.
insert into order_imports
select order_id,
coalesce(coupon_code, 'NONE')
from orders;
select count(*) as inserted
from order_imports; create or replace table order_imports (
order_id integer,
customer_email varchar not null default 'unknown@example.com'
);
insert into order_imports (order_id)
values (1);
select *
from order_imports;
A DEFAULT and a NOT NULL rule work together rather
than against each other: the rule still rejects an explicit null, and the default only covers the case where the column was not mentioned
at all.
Filling nulls with a placeholder makes the insert succeed and hides the
question. 'NONE' in 18 of 24 rows is defensible; the same trick
with 'unknown@example.com' across 4,000 rows is worse than
4,000 rejected rows, because nothing will fail again to remind you.
Substitute a value only when the placeholder means something to whoever
reads the table.
How other engines word it
| Engine | Message |
|---|---|
| DuckDB | Constraint Error: NOT NULL constraint failed: order_imports.customer_email |
| PostgreSQL | ERROR: null value in column "customer_email" of relation "order_imports" violates not-null constraint |
| MySQL | Column 'customer_email' cannot be null |
| SQL Server | Cannot insert the value NULL into column 'customer_email'; column does not allow nulls. INSERT fails. |
| SQLite | NOT NULL constraint failed: order_imports.customer_email |
Related errors
- Fix “Failing Row Contains” Constraint Errors in SQL
An INSERT or UPDATE broke a NOT NULL or CHECK rule on the table. The detail line shows the row.
- Fix “CHECK Constraint Failed” in SQL
A value is storable but breaks a business rule the table enforces. Read the expression.
- Fix “Duplicate Key Violates Primary Key Constraint” in SQL
The key you are inserting already exists. Find the existing row before you write.
Learn more
Related
Rules the table checks on every write, and the NULL a CHECK lets in.
NOT NULL, DEFAULT, CHECK, UNIQUE, and keys.
Read the line that names the constraint, not the row.
The key already exists. Find the row that holds it.
A child points at a missing parent, or a parent has children.
A value breaks a business rule the table enforces.