DEV Community

Amichay Ilan
Amichay Ilan

Posted on AI-assisted

Supabase's October 30 change: fix error 42501 without opening your data

On October 30, 2026, Supabase stops exposing new tables to its Data API by default in existing projects. If your app was built with Lovable, Bolt or Cursor, you'll likely meet this the first time you add a table, and the quickest fix your AI tool offers can make that table readable by anyone.

What changes

  • From October 30, new tables you create in the public schema of an existing project can't be reached through the Data API (supabase-js, /rest/v1, GraphQL) until you grant access. Most new projects have worked this way since late May.
  • Tables you already have keep their grants and keep working.
  • Apps that connect to Postgres directly are not affected.

Source: Supabase changelog

What you'll see

The first query against a new table fails with:

code:    "42501"
message: "permission denied for table your_table"
hint:    "Grant the required privileges to the current role with:
          GRANT SELECT ON public.your_table TO anon;"
Enter fullscreen mode Exit fullscreen mode

The trap

Paste that error into an AI coding tool and it will usually do what the hint says, or go further and grant everything on every table.

A grant decides whether a role can reach a table. Row-level security (RLS) decides which rows it gets. If the table has no RLS, a grant to anon makes every row readable by anyone who opens your site, because the anon key ships in your JavaScript. Grant insert, update or delete as well, and the rows become writable too.

The safe fix

Do all three steps in the same migration. Replace your_table and user_id with your table and its owner column.

-- 1. Grant only what the app needs
grant select, insert, update, delete on public.your_table to authenticated;
-- Server code (Edge Functions) that uses the service role needs it too:
grant select, insert, update, delete on public.your_table to service_role;
-- Grant select to anon only if logged-out visitors must read this table.

-- 2. Turn on row-level security
alter table public.your_table enable row level security;

-- 3. Let each user reach only their own rows
create policy "owners manage their rows"
  on public.your_table for all
  to authenticated
  using (auth.uid() = user_id)
  with check (auth.uid() = user_id);
Enter fullscreen mode Exit fullscreen mode

If you hand this to your AI tool, ask it to keep the three steps together and never to use using (true) on tables that hold user data.

Check the tables you already have

It takes two minutes. Run this in the Supabase SQL Editor:

select c.relname as table_name,
       c.relrowsecurity as rls_enabled,
       has_table_privilege('anon', c.oid, 'select') as anon_can_read,
       has_table_privilege('authenticated', c.oid, 'select') as signed_in_can_read
from pg_class c
where c.relnamespace = 'public'::regnamespace
  and c.relkind in ('r', 'p')
order by rls_enabled, table_name;
Enter fullscreen mode Exit fullscreen mode
  • rls_enabled false and anon_can_read true: anyone with your site's public key can read every row.
  • rls_enabled false and signed_in_can_read true: anyone who signs up can read every row.
  • rls_enabled true: the policies decide. Make sure none of them say using (true) on user data.

Missing row-level security is one of the most common holes in apps built with AI tools. I review those apps before launch, and the full guide, with copy buttons for the SQL, is at liftoffreview.com/supabase-oct-30. Happy to answer questions in the comments.

Top comments (1)

Collapse
 
cekuu35 profile image
Cenk KURTOĞLU •

The "paste the error into your AI tool" trap is real — the hint in the error message literally suggests the fix that opens the table. Two additions that make the preparation complete:

1. You can find out whether you're affected before October 30, on the real schema:

begin;
revoke all on all tables in schema public from anon, authenticated;
-- ^ what Oct 30 effectively does to *new* tables

set local role authenticated;
select * from public.your_table limit 1;
-- permission denied = this table relies on default grants
rollback;
Enter fullscreen mode Exit fullscreen mode

The rollback restores everything — the list of failures is your exact migration backlog before the date arrives.

2. The catalog check for the using (true) class on tables you already have. The warning at the end is the right instinct; this is how you audit for it instead of eyeballing policies:

select tablename, policyname, roles, qual
from pg_policies
where roles::text in ('{anon}','{public}') and qual = 'true';
Enter fullscreen mode Exit fullscreen mode

Every row returned is a table readable by anyone holding the anon key — RLS enabled, paperwork in order, data still open. From scanning public repos, the recurring shape is the "login helper" policy: written so sign-up can check whether an email exists, accidentally exposing every column of the table (three real cases with fixes: dev.to/cekuu35/3-supabase-rls-leak...).

And for teams who'll keep adding tables after the fix: alter default privileges in the same migration covers tables created later, so the 42501 class stops recurring entirely. One caveat there — a pg_dump of the project re-arms the old permissive defaults, so baselines and install templates need the same treatment (that trap and the self-healing pattern: dev.to/cekuu35/supabases-default-p...).