Back to Blog
Engineering 3 min read

Fix: "new row violates row-level security policy" in Supabase

The Supabase "new row violates row-level security policy" error means RLS blocked your insert. Here's exactly why it happens and how to fix it, with SQL examples.

By the Amex Technology Team

Fix: "new row violates row-level security policy" in Supabase — guide by Amex Technology

What This Error Means

The Supabase error new row violates row-level security policy means your INSERT (or UPDATE) was blocked because no Row-Level Security policy allowed it. RLS is enabled on the table, but no policy's WITH CHECK condition passes for the row you're trying to write.

In short: RLS defaults to deny. Enable it without a matching INSERT policy and every write fails with this exact message.

The Most Common Causes

  1. RLS is on, but there's no INSERT policy. Enabling RLS blocks everything until you add explicit policies.
  2. The WITH CHECK condition fails. A policy exists, but the row's values don't satisfy it — usually user_id not matching auth.uid().
  3. auth.uid() is null. The request isn't authenticated, so any policy comparing to auth.uid() fails.
  4. You're inserting a user_id that isn't the current user. The policy correctly rejects it.

How to Fix It

1. Add an INSERT policy

Most tables holding per-user data need a policy like this:

alter table posts enable row level security;
create policy "Users can insert their own posts"
on posts for insert
to authenticated
with check (auth.uid() = user_id);

The with check clause is what INSERT and UPDATE validate against. If it evaluates to false, you get the error.

2. Set user_id on insert

Because the policy checks auth.uid() = user_id, the row must include the current user's id:

const { data: { user } } = await supabase.auth.getUser();
await supabase.from('posts').insert({
  title: 'Hello',
  user_id: user.id, // must match auth.uid()
});

Better yet, set it at the database level with a column default of auth.uid() so the client can't get it wrong.

3. Confirm the request is authenticated

If auth.uid() is null, you're calling Supabase without a valid session. Make sure the user is logged in and you're using the authenticated client — see our guide on connecting Supabase to Next.js.

4. Don't test only in the SQL editor

The Supabase SQL editor runs as a superuser and bypasses RLS, so your insert "works" there while real users still fail. Always test as an authenticated user through your app.

How to Prevent It

  • Add policies in the same migration where you enable RLS.
  • Default user_id to auth.uid() at the database level.
  • Write separate, explicit policies for SELECT, INSERT, UPDATE, and DELETE.

Frequently Asked Questions

Why does the insert work in the SQL editor but fail from my app?

The SQL editor runs as the postgres superuser and bypasses RLS. Your app uses the anon or authenticated role, which RLS actually enforces.

Do I need a SELECT policy too?

If you return the inserted row with .select(), yes — a SELECT policy must allow reading it back, or the call still errors.

What's the difference between USING and WITH CHECK?

USING filters which existing rows a query can see or affect; WITH CHECK validates the values of new or updated rows.

Can I temporarily disable RLS to debug?

Yes, alter table posts disable row level security; — but only in development. Never ship a production table with RLS off.

Need Supabase Set Up Properly?

RLS bugs are usually a sign the auth and data layer needs a careful once-over. At Amex Technology, we design secure Supabase schemas, policies, and auth flows that just work. Explore our development services or get in touch.

Related Services

Supabase Row-Level Security Postgres Troubleshooting

Need help building this?

Our team specializes in exactly this kind of work. Get a free quote and honest assessment within 24 hours.

Start a Project
Typically responds within 4 hours

Ready to build your next digital product?

Tell us what you're building. We'll respond with a clear plan, honest scope estimate, and a timeline — no obligations.

No commitment required
Free consultation
4-hour response
No-commitmentfirst call
4hresponse time
5+ yearsexperience