Null value in column violates not-null constraint
A save left a required column empty, and that column has no default value for Postgres to fill in.
Also appears as
- null value in column "user_id" violates not-null constraint
Prompt to fix it
Saving fails with "null value in column ... violates not-null constraint". Find the column named in the error and every place that inserts or upserts into this table. Work out why the value is missing: a column with no default, a field that’s undefined in the code, or an upsert that sends only part of the row. Add database defaults where the database can fill the value (gen_random_uuid(), now(), auth.uid()), set the rest in code, and use update for partial changes. Don’t drop NOT NULL unless the field is truly optional.
Paste into Layerwise or any AI coding tool.
What it means
NOT NULL marks a column as required. This error means a row reached the table with nothing in that column, and the column has no default to fall back on. The detail line, Failing row contains (...), shows the whole row Postgres tried to save, with null where the value is missing.
JavaScript makes this easy to hit. supabase-js sends rows as JSON, and JSON drops any key whose value is undefined, so a field the code never filled in vanishes from the request. Postgres then uses the column’s default, and with no default, null.
An upsert that sends only a few fields fails here too, even when the row already exists. Postgres builds the full new row and checks it before it looks for the existing one, so every required column has to be in the payload. Use update to change part of a row.
Common causes
- The
idcolumn is auuidwith no default, so inserts that leave outidfail. - The code never sets a required field like
user_id, or sets it from a value that isundefined. - An
upsertsends only the fields being changed, so the other required columns arrive empty. - A column was made required after the code had already been saving rows without it.
How to fix it
- Find the column named in the message, and read the
Failing row containsdetail to see what was sent. - Give columns the database can fill a default:
gen_random_uuid()for IDs,now()for timestamps,auth.uid()for owner columns. - Set the remaining required values in the code before the insert, and check that none of them are
undefined. - To change part of an existing row, use
update(...).eq('id', id)instead ofupsert. - If the field is truly optional, drop the requirement with
alter table todos alter column notes drop not null;.
Example fix
-- Let the database fill values the app doesn't send.
alter table todos alter column id set default gen_random_uuid();
alter table todos alter column created_at set default now();
alter table todos alter column user_id set default auth.uid();
-- Only for a column that is really optional.
alter table todos alter column notes drop not null;Related errors
All errorsNew row violates row-level security policy
Postgres refused to save a row because no row-level security policy on that table lets the current user write it.
Duplicate key value violates unique constraint
The app tried to save a row whose ID, email, or other unique value is already in the table, so Postgres rejected the copy.
Could not find the column in the schema cache
An insert or update sent a field that Supabase’s API doesn’t know as a column of that table, so it refused the whole write.
Relation does not exist
The query names a table that Postgres can’t find in this database, usually because it was never created here or has a different name.
Build with an agent that checks its work
The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.