---
title: "Supabase 42501 permission denied: je to grant, ne RLS"
description: "Proč Supabase vrací 42501 permission denied pro tabulku, co se změní 30. října 2026 a jaký grant, RLS a politika to opraví. Reprodukováno lokálně."
url: "https://madsalt.tech/cs/notes/supabase-42501-permission-denied/"
author: "Denys Zaichenko"
language: "cs"
published: 2026-10-26
---

# Supabase 42501 permission denied: je to grant, ne RLS

TL;DR

`42501 permission denied for table …` znamená, že role nemá na tabulku grant, takže Postgres zastaví požadavek dřív, než se spustí jakákoli politika RLS. Od 30. října 2026 Supabase na stávajících projektech přestává tabulky v `public` automaticky zpřístupňovat, takže tabulky vytvořené později odpovídají 42501, dokud jim nedáte grant. Oprava jsou tři příkazy dohromady: grant pro operace, které role potřebuje, `enable row level security` a politika. Samotný grant bez RLS otevře tabulku všem.

Postavil jsem bezplatný [bezpečnostní checker pro Supabase](https://madsalt.tech/cs/tools/supabase-security-check/), který čte granty na každé zpřístupněné tabulce, a 42501 je chyba, na kterou lidé narazí, když jsou granty špatně na opačnou stranu: příliš málo místo příliš mnoho. Tady je, co znamená a co jsem viděl, když jsem ji reprodukoval.

## Co znamená chyba 42501 v Supabase?

42501 je kód Postgresu pro nedostatečné oprávnění. Postgres kontroluje dvě vrstvy, než se klient dotkne tabulky: granty rozhodují, zda role smí operaci vůbec provést, a politiky RLS rozhodují o řádcích. Chybějící grant selže první, jako chyba. Politika, která nic neodpovídá, selže tiše, jako prázdný seznam. Když tedy vidíte 42501, dívejte se na granty, ne na politiky.

PostgREST, Data API za `supabase-js`, chybu předá dál s nápovědou. Na mém lokálním stacku (Supabase CLI 2.109.1, Postgres 17.6, PostgREST 14.14) vrátil požadavek s publishable key na tabulku bez grantu pro `anon` HTTP 401 a:

```json
{
  "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"
}
```

## Proč nové tabulky dostávají 42501 po 30. říjnu 2026?

Dosud dostala nová tabulka v `public` přes výchozí oprávnění `select`, `insert`, `update` a `delete` pro `anon`, `authenticated` a `service_role`, takže byla dosažitelná přes Data API hned po vytvoření, chráněná či ne. [Changelog](https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically) Supabase tato výchozí nastavení odstraňuje: volitelně od 28. dubna 2026, jako výchozí pro nové projekty od 30. května 2026 a na všechny stávající projekty se použije 30. října 2026. Stávající tabulky si granty ponechají.

Co dalšího přepnutí rozbije a jak projekt zkontrolovat předem: [Supabase 30. října: co se rozbije a jak to ověřit](https://madsalt.tech/cs/blog/supabase-october-30-grant-change/).

Stejnou změnu jsem aplikoval na svůj lokální projekt pomocí dvou příkazů `alter default privileges … revoke` z changelogu a pak vytvořil novou tabulku `invoices`:

![Co odpoví nová tabulka po 30. říjnu 2026. Lokální Supabase s novými výchozími oprávněními, vždy jeden požadavek. Publishable key, bez grantu: create table → bez grantu → 42501, HTTP 401; Secret key, bez grantu: create table → bez grantu → 42501, HTTP 403; Po grant select a zapnutí RLS: grant select → RLS zapnuté → 0 řádků, HTTP 200.](https://madsalt.tech/charts/cs/supabase-42501-permission-denied.svg)

*Moje reprodukce na lokálním Supabase s výchozími oprávněními z changelogu Supabase, 23. října 2026.*

| Požadavek na novou tabulku                                       | Výsledek                                                             |
| ---------------------------------------------------------------- | -------------------------------------------------------------------- |
| Publishable key, bez grantu                                      | HTTP 401, 42501, nápověda `GRANT SELECT ON public.invoices TO anon;` |
| Secret key, bez grantu                                           | HTTP 403, 42501, nápověda `… TO service_role;`                       |
| Publishable key, po `grant select` a `enable row level security` | HTTP 200, `[]`, dokud politika nepovolí řádky                        |

Dvě věci mě překvapily. Secret key je odmítnut také: `service_role` obchází RLS, ale grant stejně potřebuje, takže Edge Function nebo serverová úloha, která zapisuje do nové tabulky, se rozbije stejně. A revoke bere zpět jen ty čtyři operace: nová tabulka přesto přišla s `REFERENCES`, `TRIGGER` a `TRUNCATE` pro `anon`, `authenticated` a `service_role`. Na `TRUNCATE` se žádná politika nevztahuje.

## Jak opravit 42501, aniž otevřete tabulku?

Berte grant, RLS a politiku jako jednu změnu v jedné migraci a každé roli dejte jen to, co potřebuje:

```sql
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);
```

Úvodní `revoke all` smaže `TRUNCATE`, `TRIGGER` a `REFERENCES`, které přišly s tabulkou. Na 42501 neodpovídejte příkazem `grant all on all tables in schema public to anon`: to je starý výchozí stav zpět, pro všechny tabulky najednou, a každá tabulka bez RLS se stane čitelnou pro kohokoli s vaším veřejným klíčem.

Pokud vaše tabulky vytváří AI nástroj, řekněte mu, ať granty, RLS a politiky vydává ve stejné migraci. Nápověda v chybě je napsaná tak, aby agent mohl grant opravit sám, ale jmenuje jen grant, ne RLS, které by k němu mělo přijít.

## Jak to vidí checker?

Čtyři jeho pravidla čtou vrstvu grantů: „Výchozí oprávnění, která otevírají nové objekty API“ označí projekty, které stále automaticky zpřístupňují nové tabulky, „Nepoužívaná oprávnění k zápisu pro anonymní návštěvníky“ najde zápisové granty pro `anon`, které nepoužívá žádná politika, a „Zbytečná oprávnění k tabulkám pro přihlášené uživatele“ najde `TRUNCATE`, `TRIGGER` a `REFERENCES` jako ty výše. „Politiky, které se nikdy nespustí: role nemá grant“ vypíše tabulky, kde politika uvádí roli, která pro daný příkaz nemá grant, a přesně tak vypadá nová tabulka po 30. říjnu. Proč RLS záleží i po grantu, je v článku [jak testovat Supabase RLS](https://madsalt.tech/cs/blog/how-to-test-supabase-rls/) a jak vypadají granty a politiky napříč celou aplikací, je v mém [checklistu zabezpečení Lovable aplikace](https://madsalt.tech/cs/blog/lovable-app-security-checklist/).
