ERROR: null value in column "email" of relation "patients" violates not-null constraint (SQLSTATE 23502) means an INSERT or UPDATE tried to store NULL in a column declared NOT NULL. Usually the column was simply left out of the INSERT and has no default.

Supply a value for the named column, or give the column a DEFAULT so an omitted value is filled in. The DETAIL line shows the whole failing row, which tells you exactly which values arrived.

The error

INSERT INTO patients (full_name) VALUES ('Maria Garcia');
psql:/tmp/p2.sql:9: ERROR:  null value in column "email" of relation "patients" violates not-null constraint
DETAIL:  Failing row contains (1, Maria Garcia, null, null).

Why it happens

A column you do not list in an INSERT gets its default, and a column without a DEFAULT clause defaults to NULL. The patients table declares email text NOT NULL with no default, so leaving it out produces a null and the constraint rejects the whole row. Passing NULL explicitly gives the identical message, so the error does not tell you which of the two happened; the DETAIL line does help, because it lists the row in column order: (1, Maria Garcia, null, null) is id, full_name, email and phone.

Two things in that row surprise people. The identity value 1 was already taken from the sequence, so the next successful insert got a higher id. And phone is also null, which is fine because phone allows nulls; the message names only the column that broke the rule.

The fix

INSERT INTO patients (full_name, email) VALUES ('Maria Garcia', 'maria.garcia@example.test');
INSERT 0 1

If a value can legitimately be unknown at insert time, a default keeps the NOT NULL guarantee and stops inserts from failing:

ALTER TABLE patients ALTER COLUMN email SET DEFAULT 'unknown@example.test';
INSERT INTO patients (full_name) VALUES ('David Chen');
INSERT 0 1
SELECT id, full_name, email FROM patients ORDER BY id;
 id |  full_name   |           email
----+--------------+---------------------------
  3 | Maria Garcia | maria.garcia@example.test
  4 | David Chen   | unknown@example.test
(2 rows)

Note the ids 3 and 4: the two failed inserts consumed 1 and 2. A default only helps when the column is omitted; an explicit NULL in the VALUES list still fails. Dropping the constraint is the last resort, not the fix. From .NET, Npgsql raises a PostgresException with SqlState 23502.

How it was reproduced

A postgres:18 container (PostgreSQL 18.4, Debian build 18.4-1.pgdg13+1) on Docker 29.9.2. The table was patients (id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY, full_name text NOT NULL, email text NOT NULL, phone text). One insert left email out and a second passed NULL explicitly; both failed with the same message. The script ran with psql -a -f inside the container, and a run with \set VERBOSITY verbose printed the code as ERROR: 23502 together with a COLUMN NAME: email field.

Frequently asked

What does 'null value in column violates not-null constraint' mean in PostgreSQL?
An INSERT or UPDATE tried to store NULL in a column declared NOT NULL. The message names the column and table, and the DETAIL line shows the full failing row in column order.
Why do I get a null when I did not pass NULL?
A column left out of an INSERT receives its default, and a column with no DEFAULT clause defaults to NULL. List the column with a value, or add a default with ALTER TABLE ... ALTER COLUMN ... SET DEFAULT.
Does a column default fix an explicit NULL?
No. A default is used only when the column is omitted from the INSERT. If your code sends NULL on purpose, the NOT NULL constraint still rejects it and you must send a real value.

More decoded errors in the Fixes category. For when to use NOT NULL and defaults in the first place, see constraints in Database Design for Developers.