Guides by TICWays to earnPlatformsReality checkFree toolsRecipe Pack

Answers

null value in column "user_id" of relation "notes" violates not-null constraint

checked 2026-10-09

Short answer. This is a plain data error, not a security one: your insert did not send a value for an owner column that cannot be empty. Let the database fill it in by setting the column default to auth.uid(), and keep an insert policy that checks the owner. Tested on 2026-10-09.

By Tori, last checked 2026-10-09. Every source is linked and was read on the date shown.

SQLSTATE 23502. The column and table names will be yours. This is a plain data error, not a security one: the row arrived with no value in a column that must have one.

What causes it, in plain words

You have an owner column such as user_id uuid not null, and the insert (from your app, a Lovable or Bolt generated form, an edge function) did not include it. Nothing fills it in automatically, so Postgres refuses the row.

The fix

Let the database fill in the logged-in user, so the client cannot forget it or lie about it:

alter table public.notes
  alter column user_id set default auth.uid();

Existing rows are untouched; only new inserts use the default. Keep an insert policy that checks the owner, for example with check (auth.uid() = user_id), so the default and the policy agree.

Why you might see a different error instead

This surprised me in testing, so it is worth knowing. The order of checks matters:

So if you were told "it is an RLS problem" and the message says not-null, or the other way round, both can be the same missing user_id.

Evidence: tested

Tested on 2026-10-09 on a throwaway local PostgreSQL 16.15 cluster with stand-in roles and an auth.uid() that reads the request claim (plain PostgreSQL, not a live Supabase project).

Case Result
Loose insert policy, insert without user_id ERROR 23502, the message above
Default auth.uid() set, same insert, logged in row inserted with the user's id
Default set, not logged in, loose policy ERROR 42501 (row-level security), policy blocks first
Strict policy, no default, insert without user_id ERROR 42501 (row-level security)

Check before running on an existing production table: setting a default does not backfill old rows, and it changes behaviour for every client that inserts.

Official docs

Supabase, "Row Level Security" guide: https://supabase.com/docs/guides/database/postgres/row-level-security (read 2026-10-09). It states that auth.uid() returns null when the request has no authenticated user, which is why a default of auth.uid() only works for logged-in requests.

One free check

Insert policies that "check nothing" (like the loose one above) are the thing this error teaches you to look for. TIC's free RLS auditor is a read-only SQL file you run in your own SQL editor; it flags insert policies that check nothing, among other things. A quick preflight, not a full audit: https://ticassociation.com/supabase-rls-audit?utm_source=agent-c13&utm_medium=guide&utm_campaign=supabase-null-value-in-column-user-id-violates-not-null-constraint

Questions

What does null value in column user_id violates not-null constraint mean?
The row arrived with no value in a column that must have one. The code is 23502.

How do I make Supabase fill in user_id for me?
Set the column default to auth.uid(), so the logged-in user is stored without the client sending it.

Does the default change existing rows?
No. Only new inserts use the default.

Why do I sometimes see a row-level security error instead?
If a policy checks the owner column, it can reject the row before the not-null check runs. The page explains how to tell which one you have.

Keep reading