In breve
42501 permission denied for table … significa che il ruolo non ha alcun grant sulla tabella, quindi Postgres ferma la richiesta prima che giri una qualsiasi policy RLS. Dal 30 ottobre 2026 Supabase smette di concedere automaticamente le nuove tabelle di public sui progetti esistenti, quindi le tabelle create dopo rispondono 42501 finché non le concede lei. La correzione sono tre istruzioni insieme: un grant per le operazioni che servono al ruolo, enable row level security e una policy. Concedere senza attivare la RLS apre la tabella a tutti.
Ho costruito un checker di sicurezza per Supabase gratuito che legge i grant di ogni tabella esposta, e 42501 è l’errore che si incontra quando i grant sono sbagliati nell’altra direzione: troppo pochi invece di troppi. Ecco cosa significa e cosa ho visto quando l’ho riprodotto.
Cosa significa l’errore 42501 in Supabase?
42501 è il codice Postgres per privilegi insufficienti. Postgres controlla due livelli prima che un client tocchi una tabella: i grant decidono se il ruolo può eseguire l’operazione, e le policy RLS decidono quali righe. Un grant mancante fallisce per primo, come errore. Una policy che non corrisponde a nulla fallisce in silenzio, come elenco vuoto. Quando vede 42501, guardi quindi i grant, non le sue policy.
PostgREST, la Data API dietro supabase-js, passa l’errore con un suggerimento. Sul mio stack locale (Supabase CLI 2.109.1, Postgres 17.6, PostgREST 14.14), una richiesta con la publishable key a una tabella senza grant per anon ha restituito HTTP 401 e:
{
"code": "42501",
"details": null,
"hint": "Grant the required privileges to the current role with: GRANT SELECT ON public.orders TO anon;",
"message": "permission denied for table orders"
}
Perché le nuove tabelle ricevono 42501 dopo il 30 ottobre 2026?
Finora una nuova tabella in public riceveva select, insert, update e delete per anon, authenticated e service_role tramite i privilegi predefiniti, quindi era raggiungibile dalla Data API nel momento in cui veniva creata, protetta o no. Il changelog di Supabase toglie quei default: facoltativo dal 28 aprile 2026, predefinito per i nuovi progetti dal 30 maggio 2026 e applicato a tutti i progetti esistenti il 30 ottobre 2026. Le tabelle esistenti mantengono i loro grant.
Cos’altro rompe il passaggio e come controllare il progetto prima: Supabase, cambio dei grant del 30 ottobre: cosa controllare.
Ho applicato la stessa modifica al mio progetto locale con le due istruzioni alter default privileges … revoke del changelog, poi ho creato una nuova tabella invoices:
| Richiesta alla nuova tabella | Risultato |
|---|---|
| Publishable key, nessun grant | HTTP 401, 42501, suggerimento GRANT SELECT ON public.invoices TO anon; |
| Secret key, nessun grant | HTTP 403, 42501, suggerimento … TO service_role; |
Publishable key, dopo grant select ed enable row level security |
HTTP 200, [] finché una policy non consente delle righe |
Due cose mi hanno sorpreso. Anche la secret key viene rifiutata: service_role aggira la RLS, ma ha comunque bisogno di un grant, quindi una Edge Function o un job lato server che scrive in una nuova tabella si rompe allo stesso modo. E il revoke toglie solo quelle quattro operazioni: la nuova tabella è arrivata comunque con REFERENCES, TRIGGER e TRUNCATE per anon, authenticated e service_role. Nessuna policy si applica a TRUNCATE.
Come si risolve 42501 senza aprire la tabella?
Tratti il grant, la RLS e la policy come un’unica modifica, in un’unica migrazione, e dia a ciascun ruolo solo ciò che gli serve:
revoke all on table public.invoices from anon, authenticated;
grant select, insert, update on table public.invoices to authenticated;
grant select, insert, update, delete on table public.invoices to service_role;
alter table public.invoices enable row level security;
create policy "Owners read their invoices"
on public.invoices for select
to authenticated
using ((select auth.uid()) = user_id);
Il revoke all iniziale toglie prima TRUNCATE, TRIGGER e REFERENCES arrivati con la tabella. Non risponda a 42501 con grant all on all tables in schema public to anon: è il vecchio default che torna, per tutte le tabelle insieme, e ogni tabella senza RLS diventa leggibile da chiunque abbia la sua chiave pubblica.
Se uno strumento di IA crea le sue tabelle, gli dica di emettere grant, RLS e policy nella stessa migrazione. Il suggerimento nell’errore è scritto in modo che un agente possa correggere da solo il grant, ma nomina solo il grant, non la RLS che dovrebbe accompagnarlo.
Come lo vede il checker?
Quattro delle sue regole leggono il livello dei grant: “Privilegi predefiniti che aprono i nuovi oggetti all’API” segnala i progetti che concedono ancora automaticamente le nuove tabelle, “Grant di scrittura inutilizzati per visitatori anonimi” trova i grant di scrittura di anon che nessuna policy usa, e “Grant di tabella superflui per gli utenti autenticati” trova TRUNCATE, TRIGGER e REFERENCES come quelli qui sopra. “Policy che non girano mai: il ruolo non ha il grant” elenca le tabelle in cui una policy indica un ruolo senza grant per quel comando, ed è così che appare una nuova tabella dopo il 30 ottobre. Perché la RLS conta ancora dopo il grant lo spiega come testare la Supabase RLS, e come appaiono grant e policy in un’intera app è nella mia checklist di sicurezza per le app Lovable.