Fix guides / Supabase: "new row violates row-level security policy"

How to fix "new row violates row-level security policy" in Supabase

Your app worked in the preview, then saving a record fails with error code 42501 and the message new row violates row-level security policy for table. Here is what it means and how to fix it without opening your database to the world.

What the error means

Supabase tables have Row Level Security (RLS). When RLS is on and no policy allows an action, Postgres refuses it. An insert fails with 42501: new row violates row-level security policy. This is a safety feature, not a bug in Supabase. AI builders often turn RLS on (good) but forget to add an insert policy, or write one that does not match how the app sends data.

The 3 most common causes

  1. No INSERT policy at all. There is a SELECT policy, so reading works, but nothing allows writing.
  2. The user is not logged in when the insert runs. The request uses the anon role, so auth.uid() is null and a policy like auth.uid() = user_id fails.
  3. The app does not send user_id, or sends a different value than the logged-in user's id.

Step 1: check your policies

In the Supabase dashboard open Authentication, then Policies, and find the table. Or run this in the SQL editor:

select policyname, cmd, roles, qual, with_check
from pg_policies
where tablename = 'your_table';

Step 2: add a safe insert policy

For a table where each row belongs to a user (a user_id uuid column referencing auth.users):

create policy "Users can insert their own rows"
on public.your_table
for insert
to authenticated
with check ( (select auth.uid()) = user_id );

Better still, let the database fill in the owner so the app cannot get it wrong:

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

Then the front end can insert without sending user_id at all.

Step 3: make sure the request is authenticated

Log the session right before the insert:

const { data: { session } } = await supabase.auth.getSession();
console.log('logged in as', session?.user?.id);

If this prints undefined, the insert runs as anon. Fix the login flow, or wait for the session to load before saving.

What not to do

  • Do not disable RLS to make the error go away. Anyone with your public anon key (it ships in your front end) could then read and change every row.
  • Do not add a policy with check (true) for the anon role unless the table is meant to be a public form, like a waitlist, and even then limit the columns.
  • Do not put the service_role key in front-end code. It bypasses RLS completely.

Quick checklist

  • RLS on, with explicit SELECT, INSERT, UPDATE, DELETE policies as needed
  • Insert policy targets authenticated
  • user_id defaults to auth.uid()
  • Session exists when the insert runs
Still stuck? No shame in it: these bugs hide in settings your AI builder cannot see. Send us the error and your repo and we will fix it as a pull request within 24 hours, explained in plain English, for $49. Not fixed means full refund.
Request a fix

Last updated 2026-10-19.