This error means Row Level Security (RLS) is switched on for the table, but no policy allows the operation you're trying. The same cause often shows up as a query that quietly returns [] even though the table has data.
AI coding tools often get stuck in a loop here. They can see your code but not your database policies, so they keep rewriting the insert. The fix belongs in the database, not in the code.
Step 1: See which policies exist
In the Supabase SQL editor:
select tablename, policyname, cmd, roles, qual, with_check
from pg_policies
where tablename = 'your_table';No row for the operation you need (INSERT, SELECT, UPDATE, DELETE) means it's blocked.
Step 2: Make sure rows record their owner
Most apps scope rows to the logged-in user. Your table needs a column for that:
alter table your_table
add column if not exists user_id uuid references auth.users default auth.uid();Step 3: Add the policies you actually need
create policy "insert own rows" on your_table
for insert to authenticated
with check ((select auth.uid()) = user_id);
create policy "read own rows" on your_table
for select to authenticated
using ((select auth.uid()) = user_id);
create policy "update own rows" on your_table
for update to authenticated
using ((select auth.uid()) = user_id)
with check ((select auth.uid()) = user_id);usingcontrols which existing rows you can see or change.with checkcontrols which new or updated rows are allowed.
Step 4: Check the request is really authenticated
If the user isn't logged in when the insert runs, auth.uid() is null and the policy fails. Confirm there's a session before writing, and that you're not inserting a user_id that differs from the logged-in user.
Step 5: Don't "fix" it by turning RLS off
Disabling RLS, or adding a using (true) policy for everyone, makes the error go away by making the table readable or writable by anyone with your public anon key. That key is visible in your frontend code by design.
Step 6: Test like an outsider
- Log in as user A and create a row.
- Log in as user B: you should not see user A's row.
- Log out completely and query the table: you should get nothing back.
- Run Supabase's Security Advisor to find tables with RLS turned off.
Run a free ReplayWatch scan. Paste your live URL and ReplayWatch checks it for page load, security headers, secrets exposed in your HTML/JS, Supabase/Firebase data that is readable without login, broken links and assets, SEO tags, and whether your signup page is reachable. It does not log in or run your signup flow. → https://replaywatch.com/#scan