VibeCPR

← All fixes

Supabase · RLS

Fix "new row violates row-level security policy for table" (Supabase)

Updated · Applies to: Supabase, Lovable, Bolt, v0, Cursor, Replit

TL;DR fix: Row Level Security is on, but no policy allows this write for the role making the request. Add an INSERT policy with a WITH CHECK clause (for example (select auth.uid()) = user_id), make sure the insert actually sets user_id to the signed-in user, and add a SELECT policy if your code chains .select() after the insert. Never "fix" it by disabling RLS.

Steps

  1. Read the table name in the error. The message names the table, e.g. new row violates row-level security policy for table "messages". That is the table that needs a policy.
  2. Check which policies exist for that table. In the Supabase dashboard open Authentication → Policies (or the table in Table Editor) and look for a policy covering the operation that failed: INSERT, UPDATE, or SELECT.
  3. Add a policy with WITH CHECK for inserts. INSERT policies are written with a WITH CHECK expression. UPDATE policies need USING (which rows) and WITH CHECK (what the new row may look like).
  4. Make sure the row passes the check. If the policy compares auth.uid() to user_id, the insert must set user_id to the signed-in user's id, or the column needs default auth.uid(). The user must actually be logged in, otherwise the request runs as anon.
  5. Add a SELECT policy if you use insert().select(). supabase-js .insert().select() reads the new row back. Without a SELECT policy that allows it, the call fails with the same 42501 error.
  6. Retest as a real user. Log in as a normal user in the app (not the SQL editor, which bypasses RLS) and retry the action.

The fix in SQL

Run this in the Supabase SQL editor. Replace messages and user_id with your table and owner column:

-- Make sure RLS is on (it should be)
alter table public.messages enable row level security;

-- Let signed-in users insert rows they own
create policy "users insert own rows"
  on public.messages for insert
  to authenticated
  with check ((select auth.uid()) = user_id);

-- Let them read their own rows (needed for .insert().select())
create policy "users read own rows"
  on public.messages for select
  to authenticated
  using ((select auth.uid()) = user_id);

-- Optional: fill user_id automatically so the frontend can't get it wrong
alter table public.messages alter column user_id set default auth.uid();

Supabase’s docs describe the insert case directly: “The with check expression ensures that any new row adheres to the policy constraints, so a user cannot create a row that belongs to someone else.”

Why AI-built apps hit this so often

App builders usually create the table, turn on RLS, and wire up the form in separate steps. When the policy step is skipped or written only for SELECT, every save fails. The dangerous “fix” an AI tool may suggest is disable row level security or with check (true), which makes the error disappear by letting anyone write to your table.

Prompt for Cursor, Lovable or Bolt

Inserts into public.<table> fail with "new row violates row-level security policy".
Do NOT disable RLS and do NOT use USING (true) / WITH CHECK (true).
Add an INSERT policy for authenticated with WITH CHECK ((select auth.uid()) = user_id),
a matching SELECT policy, and set user_id default auth.uid(). Show me the SQL first.

Related: Supabase’s October 30, 2026 change and “permission denied for table”.

When to get help

Get help if the policy needs to depend on teams, roles or joins between tables, if your AI tool keeps "fixing" this by disabling RLS or using USING (true), or if you're not sure which tables are currently readable by anyone with your public key.

FAQ

What does "new row violates row-level security policy" mean?

It means Row Level Security is enabled on the table and no policy allows the current role (anon or authenticated) to write that row. Postgres returns error code 42501 and the Supabase API returns HTTP 403. The fix is to add or correct an INSERT or UPDATE policy with a WITH CHECK clause, not to disable RLS.

Why does the same insert work in the Supabase SQL editor?

The SQL editor runs as a privileged database role that bypasses Row Level Security. Your app runs as anon or authenticated, so policies apply. Always test policies through the app or by impersonating a user.

Should I just disable RLS to make the error go away?

No. With RLS disabled, anyone with your public anon or publishable key can read and change that table. That is the misconfiguration behind CVE-2025-48757 in Lovable apps. Write the missing policy instead.

Is this the same as "permission denied for table"?

No. "permission denied for table" (also 42501) means the role has no GRANT on the table at all, which is common for new tables after Supabase's October 30, 2026 change. "new row violates row-level security policy" means the grant exists but an RLS policy blocked the row.

Sources

Related fixes