Rowpass 42501: permission denied for table Not affiliated with Supabase

Rowpass / Guides

Which grant does each call need?

Tick what your code does. Copy the smallest grant that makes it work.

What does your code call on this table?
Who calls it?
grant select, insert on public.your_table to authenticated;

Needs SELECT, INSERT on the table, plus USAGE on the sequence if the id column is serial.

The rule behind each row

CallSQL it becomesTable privilegesWhy
.select()selectSELECTReading rows needs SELECT.
.insert()insertINSERTInserting needs INSERT. Rows are not returned unless you chain .select().
.insert().select()insert ... returningINSERT, SELECTReturning the new row needs SELECT on the returned columns as well.
.update().eq()update ... whereSELECT, UPDATEA filter reads columns to find the rows, so UPDATE alone is not enough.
.upsert()insert ... on conflict do updateINSERT, SELECT, UPDATEThe conflict path is an update, and the conflict column is read.
.delete().eq()delete ... whereDELETE, SELECTA filter reads columns to find the rows, so DELETE alone is not enough.

Three of these surprise people:

  • Update and delete need SELECT. The PostgreSQL manual: any nontrivial UPDATE command will require SELECT privilege as well. The filter in .eq() reads a column.
  • Upsert needs UPDATE. The manual: If ON CONFLICT DO UPDATE is present, UPDATE privilege on the table is also required.
  • Chaining .select() needs SELECT. The client reference says: By default, inserted rows are not returned. To return it, chain the call with .select(). Returning rows is a read.

For each call we granted exactly the privileges in the table, ran the statement, then removed one privilege at a time and confirmed Postgres answered permission denied for table.

Tested on the SQL statements in Postgres (PGlite), not through a hosted project. The Data API may send a slightly different statement for the same call; if a call still fails, the hint in the error names the missing privilege.

A grant is half of it

A grant lets the role reach the table. With row level security on, a policy must also allow the rows. See which policy each command needs, or paste your table into the tool below to get grants and policies together.

Write the fix for your tables

One table is free. The whole schema with a rollback file is $9 one-time.

 

Waiting for a paste.

    Who can reach each table

    Your tables show up here, one row each, with a choice of who can reach them.

    The SQL appears here as soon as a table is found.

    Parsed in your browser. Your SQL is never uploaded, and no site or database is scanned.

    Questions

    Why does update fail when I granted UPDATE?

    Because the statement has a filter. Finding the rows to change reads the table, and reading needs SELECT. Grant SELECT and UPDATE together.

    Does insert need a grant on the sequence?

    Only when the id column takes its value from a sequence, as serial and bigserial columns do. Then the role also needs USAGE on that sequence. A uuid default needs nothing extra.

    Should I just grant all four?

    It works, and it gives the role more than it uses. Supabase recommends granting each role only what it needs. If signed-out visitors only read, grant anon SELECT and nothing else.

    Sources

    Related

    Did it fix your error?