DEV Community

FixLoop
FixLoop

Posted on Originally published at fixloop.dev

Supabase select returns [] with no error: 5 RLS causes

You run supabase.from("posts").select("*") and get { data: [], error: null }. The rows are in the table. The same query works in the SQL editor. Your app shows nothing.

That's Row Level Security doing its job. RLS on with no matching SELECT policy filters every row out: zero rows, no error. The SQL editor runs as postgres, which owns the tables and skips RLS, so it sees everything. Your app goes through the Data API as anon or authenticated, and those roles only see rows a policy allows.

If you get 42501 permission denied for table instead, that's a missing GRANT, not this bug: the Oct 30 grants post.

1. RLS on, no SELECT policy

From the Supabase RLS docs: "Once RLS is enabled, no data is accessible through the API when using a publishable key, until you create policies."

create policy "anyone can read posts"
on public.posts
for select
using (true);
Enter fullscreen mode Exit fullscreen mode

2. Policy targets the wrong role

to authenticated never matches a signed-out visitor, or a signed-in one whose session hasn't loaded yet. For public reads use to anon, authenticated, or leave out to.

3. auth.uid() is null

using (auth.uid() = user_id) only works when the request carries the user's JWT. Without it, null = user_id is never true, so every row disappears. Usual reasons: not signed in, querying on first render before the session is ready, or server code creating a client with only the anon key.

const { data: { session } } = await supabase.auth.getSession();
console.log("uid:", session?.user?.id); // undefined = no session
Enter fullscreen mode Exit fullscreen mode

4. The rows belong to someone else

The policy is right; the data isn't. Check in the SQL editor:

select id, user_id from posts;
Enter fullscreen mode Exit fullscreen mode

user_id null or another account's id means the insert path is wrong, not the policy.

5. Policy checks the wrong column

AI-generated schemas sometimes call the owner column user_id, owner_id, or reuse id. A policy comparing auth.uid() to the row's primary key matches nothing.

Confirm it in two minutes

select polname, cmd, roles, qual
from pg_policies
where tablename = 'posts';
Enter fullscreen mode Exit fullscreen mode

No row with cmd = SELECT? That's cause 1. Then log user?.id right before the query. If it's undefined, fix auth first.

For owner-only data, this is the shape the Supabase docs use:

create policy "owners can read their posts"
on public.posts
for select
to authenticated
using ( (select auth.uid()) = user_id );
Enter fullscreen mode Exit fullscreen mode

Don't fix it by disabling RLS. That hands every row to anyone holding your publishable key.

Full guide

Longer version with the debug policy trick, the empty-array vs 42501 difference, and an FAQ:

https://fixloop.dev/guides/supabase-select-returns-empty-array


I run FixLoop. Still stuck? Paste the error and we'll email you the likely cause, free.

Top comments (0)