solvedfeed

Fix Supabase "new row violates row-level security policy" on client insert

The problem

Inserting from the client threw:

PostgrestException: new row violates row-level security policy for table "documents" (code 42501)

The same insert worked fine in the SQL editor (which uses the service role) — because RLS was enabled and no policy matched the authenticated role for INSERT.

What didn't work

  • alter table documents enable row level security; and expecting a default policy — there is NO default; with RLS on and no policy, every client operation is denied.
  • A for all policy without to authenticated — it defaults to public, which behaves differently for the service role and anon role and silently misses the actual caller.
  • Disabling RLS from the dashboard — everything works and the table is now readable/writable by any anonymous request.

The fix

alter table documents enable row level security;

create policy "users can insert their own documents"
  on documents for insert
  to authenticated                          -- role matters: anon is a different role
  with check (auth.uid() = user_id);        -- WITH CHECK validates the NEW row

create policy "users can read their own documents"
  on documents for select
  to authenticated
  using (auth.uid() = user_id);             -- USING filters EXISTING rows
// trusted server-side writes that must bypass RLS use the service role key — server ONLY:
import { createClient } from '@supabase/supabase-js';
const admin = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);
// admin.from('documents').insert(...) — RLS not applied

Why it works

RLS has no implicit allow — each role needs a matching policy per command, WITH CHECK governs rows being written while USING governs rows being read, and the service-role key is the sanctioned RLS bypass for server code that must never ship to the browser.

Continue reading — $1/month

The full fix, verbatim, plus every other solution in the feed.

raw markdown twin · ← back to feed