DEV Community

Cover image for Supabase "permission denied for table" (42501) on new tables after 30 Oct 2026: the safe fix
VibeFix
VibeFix

Posted on Edited on Originally published at vibe-fixer.com

Supabase "permission denied for table" (42501) on new tables after 30 Oct 2026: the safe fix

Your newest Supabase table returns 42501 "permission denied for table", while every older table still works. With that message on a new table, the roles your app uses through the API have no GRANT on it. Supabase no longer gives the API access to new tables in the public schema automatically, and applies this to all existing projects from 30 October 2026. Add the GRANT and turn on row level security with policies in the same step: a GRANT with row level security off lets anyone who has your publishable (anon) key read every row, and that key is in your app's front end.

A save fails, a list won't load or sign-up breaks, and the response says code 42501, "permission denied for table".

The exact error

{
  "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

Why it happens

Supabase announced on 28 April 2026 that new tables in the public schema are not reachable through the API until access is granted. It started rolling this out as the default for new projects on 30 May 2026, and applies it to all existing projects from 30 October 2026. Tables you already have keep their current access. Existing tables are not affected; the change applies to tables created after it.

Possible causes

  • A new table was created without granting access to the roles the API uses.
  • Access was granted to one role (for example signed-out visitors) but not the one the app uses (signed-in users), or the other way round.
  • It is a row-level security problem instead: Supabase also returns 42501 when row level security blocks an insert or update. Then the fix is a policy, not a grant.
  • A table with an auto-numbered column is missing access to its sequence.
  • An AI builder or script created the table and did not include the access it needs.

Why the hint is not the whole fix

The hint names the missing GRANT. It does not check row level security. Grants decide whether a role can reach a table; row level security decides which rows. If row level security is off and you run grant select ... to anon, every row can be read with the publishable (anon) key, and that key ships in your app's front end.

Supabase's advice is to treat three steps as one unit: grant the privileges, enable row level security, add the policies you need.

Fix steps

Run this SQL on your project's database. Replace your_table and user_id with your table and its owner column.

-- 1. Give the API roles access to the table
grant select, insert, update, delete on public.your_table to authenticated;
grant select, insert, update, delete on public.your_table to service_role;
-- Only if signed-out visitors really need to read it:
-- grant select on public.your_table to anon;

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

-- 3. Let each signed-in user see and change only their own rows
create policy "own rows: read" on public.your_table
  for select to authenticated using ((select auth.uid()) = user_id);
create policy "own rows: insert" on public.your_table
  for insert to authenticated with check ((select auth.uid()) = user_id);
create policy "own rows: update" on public.your_table
  for update to authenticated using ((select auth.uid()) = user_id)
  with check ((select auth.uid()) = user_id);
create policy "own rows: delete" on public.your_table
  for delete to authenticated using ((select auth.uid()) = user_id);
Enter fullscreen mode Exit fullscreen mode

If the table has an auto-numbered id, grant its sequence too:

grant usage, select on all sequences in schema public to authenticated, service_role;
Enter fullscreen mode Exit fullscreen mode

If you use migrations, put these statements in the same migration that creates the table, so the next new table does not break the same way.

Check which roles can reach the table

select grantee, privilege_type
from information_schema.role_table_grants
where table_schema = 'public' and table_name = 'your_table';
Enter fullscreen mode Exit fullscreen mode

Check that row level security is on for every public table:

select relname as table_name, relrowsecurity as rls_on
from pg_class
where relnamespace = 'public'::regnamespace and relkind = 'r'
order by 2, 1;
Enter fullscreen mode Exit fullscreen mode

Any row with rls_on = false is a table to fix before you add grants to it.

Check that the data is hidden while signed out

Run this on a table that has rows in it, using only the publishable (anon) key, the same one your app's front end uses. No sign-in token.

curl "https://YOUR-PROJECT.supabase.co/rest/v1/your_table?select=*&limit=5" \
  -H "apikey: YOUR_PUBLISHABLE_KEY"
Enter fullscreen mode Exit fullscreen mode
  • [] (empty list) on a table that has rows: signed-out visitors see nothing. This is what you want for private data.
  • Rows come back: anyone with the public key can read them. If that is not intended, check rls_on with the query above and the table's policies before anything else.
  • 42501 permission denied: signed-out visitors have no grant on this table. Fine if they should not read it.

Then sign in as one test user in your app and confirm you see your own rows and not another user's.

Why it can look fine at first

Tables you made earlier keep their access, so the pages you use most keep working. A table added after the change, for example one your AI tool just created, fails until it gets its grant.

Still broken?

If the error is gone but your live app still breaks for new users, start with a free check: Check my app free. Our AI agent signs up like a new user and shows you, with a screenshot, whether your app breaks for them. If you want it fixed, it fixes it in your code and tests your live app again.

VibeFix is independent. Supabase is a trademark of its owner.

When did you last request your newest table signed out, with only the public key?

Originally published at vibe-fixer.com. I'm building VibeFix: our AI agent fixes what breaks in your live app in your code, then tests your live app again so you see the result yourself.

Top comments (0)