DEV Community

fixkit ai
fixkit ai

Posted on Originally published at fixkit-ai.netlify.app

Supabase RLS errors in Lovable and Bolt apps (and how to fix them safely)

If you built your app with Lovable or Bolt on top of Supabase, sooner or later you'll see this:

new row violates row-level security policy for table "todos"
Enter fullscreen mode Exit fullscreen mode

That's Postgres error code 42501. Its quieter cousin is worse: a select that returns [] with no error, even though the table clearly has rows.

Why it happens

When Row Level Security (RLS) is enabled and no policy allows an action, Supabase blocks it. Common causes in AI-built apps:

  • RLS is enabled but no insert/select policy exists
  • The user isn't logged in, so auth.uid() is null
  • The insert doesn't set user_id, or sets it to a different value
  • An update policy is missing its with check

Reads and writes fail differently. A blocked select doesn't throw; rows are filtered out and you get []. A blocked insert throws the error above.

Fix 1: add owner-based policies

Run this in the Supabase SQL editor (rename todos to your table):

alter table public.todos enable row level security;

create policy "Users read own todos" on public.todos
for select to authenticated using ((select auth.uid()) = user_id);

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

create policy "Users update own todos" on public.todos
for update to authenticated
using ((select auth.uid()) = user_id) with check ((select auth.uid()) = user_id);

create policy "Users delete own todos" on public.todos
for delete to authenticated using ((select auth.uid()) = user_id);

Enter fullscreen mode Exit fullscreen mode




Fix 2: fill in user_id automatically


alter table public.todos alter column user_id set default auth.uid();
Enter fullscreen mode Exit fullscreen mode




Fix 3: make sure the user is actually signed in


const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error('Not signed in');
await supabase.from('todos').insert({ title, user_id: user.id });
Enter fullscreen mode Exit fullscreen mode




Don't "fix" it by disabling RLS or shipping the service_role key

The service_role key (and the newer sb_secret_... keys) bypasses RLS entirely. Keep it on the server only, never in frontend code. The browser should only use the anon or publishable key, and that key is only safe because RLS limits what it can do.

Prompt to paste into Lovable or Bolt

Write Supabase RLS policies so authenticated users can only select, insert, update, and delete rows where user_id = auth.uid(). Don't disable RLS and don't use the service_role key in the client.

FAQ

Why do I get empty results instead of an error? RLS filters select results silently. With no policy, you get zero rows.

Is a public read policy OK? Yes, for genuinely public data: for select to anon, authenticated using (true).


Originally published on FixKit AI. If you're seeing a different error, paste it into the free FixKit Error Fixer (disclosure: I built it). Related: CORS errors when a Lovable app calls an API.

Top comments (0)