new row violates row-level security policy for table (SQLSTATE 42501)
appears when:After RLS is enabled on a table but no INSERT policy has been written for the authenticated role
Supabase RLS blocking insert
Postgres defaults to deny when RLS is on. Every INSERT, SELECT, UPDATE, DELETE is blocked until you write a policy.
INSERT policy whose WITH CHECK evaluates true for the row. Create a policy FOR INSERT TO authenticated WITH CHECK (auth.uid() = user_id) and a matching SELECT policy so the chained .select() can read the row back.Quick fix for Supabase RLS blocking insert
01-- Single-tenant ownership pattern (most AI apps start here)02create policy "users insert own rows"03on public.tasks04for insert05to authenticated06with check (auth.uid() = user_id);07 08-- Default auth.uid() so the client cannot forget to set user_id09alter table public.tasks10alter column user_id set default auth.uid();11 12-- Verify in SQL editor13set role authenticated;14insert into public.tasks (title) values ('test') returning *;Deeper fixes when the quick fix fails
01 · Add the matching SELECT policy
01create policy "users read own rows"02on public.tasks03for select04to authenticated05using (auth.uid() = user_id);02 · Multi-tenant: join through memberships
01create policy "members insert org rows"02on public.tasks03for insert04to authenticated05with check (06 organization_id in (07 select organization_id from memberships08 where user_id = auth.uid()09 )10);03 · Write a pgTAP regression test
01-- tests/rls_tasks.sql — asserts cross-tenant writes fail02begin;03select plan(1);04 05set local role authenticated;06set local "request.jwt.claims" = '{"sub":"user-a-uuid"}';07 08select throws_ok(09 $$insert into public.tasks (user_id, title) values ('user-b-uuid', 'test')$$,10 '42501',11 'cross-user insert must be blocked by RLS'12);13 14select * from finish();15rollback;Why AI-built apps hit Supabase RLS blocking insert
Lovable, Bolt, Base44, and Cursor all ship apps that talk to Supabase. In preview the generated code uses the service_role key, a superuser role that bypasses RLS entirely. Every operation succeeds regardless of policies because the database never evaluates them. The preview gives the model no feedback that policies are missing, so the model never writes them. The app appears complete.
At deploy the client switches to the anon key or the authenticated role — non-privileged roles that trigger RLS. Postgres default when RLS is enabled and no policy matches is deny. Your INSERT returns SQLSTATE 42501 if the client used .insert() alone, or returns a 200 with an empty array if the INSERT is chained to .select() and RLS also blocks the follow-up read. Either failure is indistinguishable from an app bug if you do not know to check the Postgres log.
The third variant is an INSERT policy that exists but has the wrong WITH CHECK. A common AI-generated mistake is a policy whose USING matches the user but whose WITH CHECK is missing or set to true. Postgres evaluates only WITH CHECK for INSERT; the USING clause is ignored. The policy looks written, the table looks protected, inserts still fail or silently succeed for unrelated rows.
Supabase RLS blocking insert by AI builder
How often each AI builder ships this error and the pattern that produces it.
| Builder | Frequency | Pattern |
|---|---|---|
| Lovable | Every Supabase scaffold | Uses service_role in preview; ships with no policies |
| Bolt.new | Common | Writes USING instead of WITH CHECK on INSERT |
| Base44 | Common | FOR ALL WITH CHECK (true) — identical to no protection |
| Cursor | Sometimes | Leaves user_id nullable with no default auth.uid() |
| Replit Agent | Rare | Targets policies at `public` role — includes anon |
Related errors we fix
Stop Supabase RLS blocking insert recurring in AI-built apps
- →Never use service_role in preview — test with anon + authenticated so the model gets RLS feedback.
- →Always set the ownership column default to `auth.uid()`.
- →Pair every INSERT policy with a matching SELECT policy for the same role.
- →Ship a pgTAP test suite asserting cross-tenant writes fail with 42501.
- →Scope policies to `authenticated`, never `public` — `public` includes anon.
Still stuck with Supabase RLS blocking insert?
Supabase RLS blocking insert questions
What does Postgres error 42501 mean on an INSERT?+
Why does my INSERT return PGRST116 instead of 42501?+
Does enabling RLS without policies block all inserts?+
What is the difference between USING and WITH CHECK in an INSERT policy?+
How long does a full Supabase RLS audit take?+
Ship the fix. Keep the fix.
Emergency Triage restores service in 48 hours. Break the Fix Loop rebuilds CI so this error cannot ship again.
Hyder Shah leads Afterbuild Labs, shipping production rescues for apps built in Lovable, Bolt.new, Cursor, Replit, v0, and Base44. our rescue methodology.