Supabase Row-Level Security Silently Returning Empty
RLS returning empty instead of an error is the most common Supabase debugging pit. How to spot it, how to debug it, how to design around it.
RLS returning empty instead of an error is the most common Supabase debugging pit. How to spot it, how to debug it, how to design around it.
Pain Point
Supabase RLS returns empty instead of an error. How to spot the silent fail, how to debug it, and how to design your code so it never surprises you.
You write a query. Locally it returns three rows. In production it returns an empty array. No error. No log. Just empty.
This is RLS doing exactly what it should: filtering out rows the user is not allowed to see. The problem is that it does so silently, and your client code happily renders an empty state as if the data were truly missing.
I burned half a day on this the first time. It is worth learning the shape before it hits you.
select from a table with RLS on.auth.uid() does not match any row policy.{ data: [], error: null }.Not an auth error. Not a permission error. Just empty.
Three things, in order:
auth.uid() in the query. supabase.rpc('debug_uid') that returns auth.uid(). If it is null, your session is not being forwarded.SELECT * FROM pg_policies WHERE tablename = ''your_table'';. Check the USING clause matches what you expect.SET LOCAL role = authenticated; SET LOCAL request.jwt.claim.sub = ''<user_id>''; then run the query. If it returns empty here, RLS is the cause.Always read auth.uid() first in your code path. If it is null before you even hit the database, show an auth error, not an empty state. If it is set but the query returns empty, log it with the user id so you can tell silent-RLS from real-empty.
On the server side: wrap cross-user queries in a service-role client so RLS does not apply, and enforce authorization yourself explicitly. The service-role client belongs on the backend, never in the mobile bundle.
AI App Factory ships a Supabase wrapper that logs auth.uid() on every query in development, and flags empty results so you see them in the console. It also separates the anon-key client (mobile) from the service-role client (backend) by construction.
AI App Factory handles the boring infrastructure so you can build the product.