Início / RLS / Erro 42501: permission denied for table · Read in English

Supabase RLS · Correção de erro

Erro 42501: permission denied for table

Postgres 15 · Supabase✓ código testado num banco de verdade
TL;DR

O role (anon, authenticated ou service_role) não tem privilégio na tabela, então o Postgres barra a query antes mesmo de o RLS rodar. Dê grant só daquela tabela, só pro role que precisa, na mesma migration que cria a tabela. Nunca resolva com grant ... on all tables.

01 Grants e RLS: duas trancas diferentes

Toda query que chega pela Data API passa por duas verificações. Os grants decidem se um role pode tocar na tabela. O RLS decide depois quais linhas. 42501 permission denied for table invoices significa que a primeira tranca falhou, então suas policies nem foram consultadas. Problema de RLS tem outra cara: zero linhas, ou new row violates row-level security policy.

02 De onde vem

CAUSA 1 · tabelas novas

Tabela criada depois da mudança de grants do Supabase

Tabelas novas não ganham mais grants automáticos pros roles da API. A primeira query numa tabela nova devolve 42501 até você dar o grant. O que mudou em 30/10 e por que importa.

CAUSA 2

Tabela em outro schema

O role também precisa de usage no schema; sem isso, a mensagem é permission denied for schema app.

CAUSA 3

O grant foi revogado ou nunca foi dado pra esse role

Por exemplo, grant pra authenticated, mas quem chama é um visitante deslogado (anon). A Data API responde 401 pra anon e 403 pra authenticated.

03 A correção: grant por tabela, com RLS na mesma migration

migration.sql

alter table public.invoices enable row level security;

create policy "owner reads" on public.invoices for select to authenticated
  using (user_id = (select auth.uid()));

-- só o role e as operações que o app realmente usa
grant select on public.invoices to authenticated;

Pra tabela em outro schema, adicione também grant usage on schema app to authenticated;

04 A correção que vaza

-- não cole isso pra sumir com o erro
grant select on all tables in schema public to anon, authenticated;

Some com o 42501 e libera também todas as outras tabelas de public. Qualquer uma com RLS desligado vira leitura livre pra quem tiver sua anon key pública. Confira o que cada role alcança antes e depois de qualquer grant:

check.sql

select c.relname,
       has_table_privilege('anon', c.oid, 'select') as anon_can_read,
       c.relrowsecurity as rls_on
from pg_class c join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public' and c.relkind = 'r'
order by 1;

Linha com anon_can_read = true e rls_on = false é tabela pública. O guia da mudança de grants tem uma versão mais rigorosa, que também pega grants de coluna e views.

Se for escrever as policies do zero, o gerador de policies RLS monta a migration com RLS, policies e só os grants necessários (em inglês).

◆ GRÁTIS · MIT · npm + GitHub Action

Pegue isso antes de ir pro ar

airlock-rls é um gate de CI que quebra o build quando uma tabela vai pro ar exposta ou uma policy é permissiva: o mesmo tipo de bug, pego no CI contra um banco com as suas migrations aplicadas, antes de chegar em produção.

npx airlock-rls→

Ou comece pelo nextjs-supabase-starter: auth + uma tabela com RLS + um teste de isolamento, pra começar de um padrão que já vem selado.

PDF GRÁTIS

Baixe o cheat sheet de RLS do Supabase

As regras de ouro, as armadilhas que vazam em produção, policies corretas e o teste de isolamento, numa página só (em inglês).

FAQ

O 42501 é um erro de RLS?

Não. É erro de privilégio, que acontece antes do RLS. O mesmo SQLSTATE aparece quando um insert ou update falha no WITH CHECK de uma policy, mas aí a mensagem é new row violates row-level security policy, e não permission denied for table.

Preciso dar grant pro service_role também?

Se o seu backend usa a chave service_role numa tabela nova, sim. O service_role ignora o RLS, mas continua precisando do privilégio na tabela.