This error means Supabase's Row Level Security (RLS) is preventing your app from inserting data into a table. The most common cause is a missing or misconfigured INSERT policy. Add a policy that grants INSERT permission to authenticated users, and remember that Supabase also requires a SELECT policy if you want the inserted row returned.
What does "Row level security policy blocked insert" mean?
When you see "Row level security policy blocked insert" in Supabase, it means your database has Row Level Security (RLS) enabled on a table, but there is no policy that allows the current user to insert new rows. Supabase returns this as PostgreSQL error code 42501 with the message "new row violates row-level security policy for table 'TABLE_NAME'." The error is a security feature working as intended — it blocks unauthorized writes.
This error is extremely common in apps built with AI code generators like Lovable, Cursor, and V0. These tools frequently create tables with RLS enabled but forget to add the necessary INSERT and SELECT policies. The result is that your app appears to work in development (where you might be using the service_role key) but fails in production when real users try to save data.
A subtle gotcha makes this error even more confusing: Supabase's PostgREST layer returns the newly inserted row by default, which requires a SELECT policy in addition to the INSERT policy. If you only have an INSERT policy, the insert itself succeeds but the response fails — making it look like the insert was blocked when it actually went through.
Common causes
No INSERT policy exists on the table
RLS is enabled but no policy grants write access to any role
The INSERT policy uses auth.uid() but the user is
not authenticated, so the policy condition evaluates to false
A SELECT policy is missing
Supabase needs SELECT permission to return the inserted row, and without it the operation appears to fail
The policy targets the wrong
role (e.g., written for 'service_role' instead of 'authenticated' or 'anon')
The WITH CHECK expression in
the INSERT policy does not match the data being inserted (e.g., the user_id column value does not match auth.uid())
AI-generated code created the table with
RLS enabled but did not generate any policies, leaving the table locked down completely
How to fix RLS blocked insert in Supabase
Open your Supabase Dashboard, go to the SQL Editor, and add both an INSERT policy and a SELECT policy for the table. The INSERT policy should use a WITH CHECK expression that validates the user owns the row they are inserting. The SELECT policy should use a USING expression so the inserted row can be returned. If you only need the insert to succeed without returning data, you can alternatively pass { returning: 'minimal' } in your Supabase client call to skip the SELECT requirement.
After adding the policies, test by signing in as a real user in your app and attempting the insert again. If you are still blocked, check the Supabase Logs tab for the exact policy violation. For complex projects where debugging RLS is time-consuming, the team at RapidDev can audit your Supabase security policies and ensure they work correctly with your frontend code.
-- Table has RLS enabled but no policiesALTER TABLE public.posts ENABLE ROW LEVEL SECURITY;-- No INSERT or SELECT policies exist-- Add INSERT policy for authenticated usersCREATE POLICY "Users can insert their own posts" ON public.posts FOR INSERT TO authenticated WITH CHECK (auth.uid() = user_id);-- Add SELECT policy so the inserted row can be returnedCREATE POLICY "Users can view their own posts" ON public.posts FOR SELECT TO authenticated USING (auth.uid() = user_id);Prevention tips
- Always create both INSERT and SELECT policies together — Supabase needs SELECT permission to return inserted rows by default
- Use the Supabase Dashboard RLS editor (Authentication > Policies) instead of raw SQL to reduce syntax mistakes
- Test your policies using the SQL Editor with SET ROLE authenticated before running INSERT statements
- Add { returning: 'minimal' } to your Supabase client insert calls if you do not need the inserted row returned, which removes the SELECT policy requirement
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
My Supabase app shows 'new row violates row-level security policy for table'. I have RLS enabled. What INSERT and SELECT policies do I need to allow authenticated users to insert and read their own rows?
Write Supabase RLS policies for my posts table that allow authenticated users to insert rows where user_id matches their auth.uid() and select only their own rows.
Frequently asked questions
Why do I get "Row level security policy blocked insert" even though I added an INSERT policy?
You likely need a SELECT policy too. Supabase's PostgREST returns the inserted row by default, which requires SELECT permission. Add a SELECT policy or use { returning: 'minimal' } in your insert call.
How do I check which RLS policies exist on my table?
Go to your Supabase Dashboard, click Authentication in the left sidebar, then select Policies. You will see all policies grouped by table. You can also run SELECT * FROM pg_policies WHERE tablename = 'your_table'; in the SQL Editor.
Should I disable RLS to fix this error?
No. Disabling RLS removes all access controls, meaning anyone with your anon key can read and write all data. This is a serious security vulnerability. Always fix the policies instead of disabling RLS.
Why does my insert work in the Supabase Dashboard SQL Editor but fail from my app?
The SQL Editor runs as the postgres superuser role, which bypasses RLS entirely. Your app uses the anon or authenticated role, which is subject to RLS policies. Test with SET ROLE authenticated before your INSERT to simulate app behavior.
Can AI-generated code cause RLS policy issues in Supabase?
Yes, this is one of the most common problems. AI code generators like Lovable and Cursor frequently create tables with RLS enabled but forget to add INSERT and SELECT policies. Always review generated SQL migrations for missing policies.
What is PostgreSQL error code 42501 in Supabase?
Error code 42501 means 'insufficient privilege.' In Supabase, this almost always means an RLS policy is blocking the operation. Check that the correct policy exists for the operation type (INSERT, SELECT, UPDATE, DELETE) and the correct role (authenticated, anon).
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your issue.
Book a free consultation