shipfix

Common errors · Supabase

Supabase: infinite recursion detected in policy for relation

Cause A policy on a table queries that same table (directly or through another one), so Postgres evaluates the policy again and loops.
Fix Move the membership lookup into a SECURITY DEFINER function with a pinned search_path and call it from the policies.

infinite recursion detected in policy for relation "members"

Have it fixed for you, 290 EURSee the fix step by step

What you receive a diff on a branch of your repository, and a correction note: root cause, change made, how to verify it. See a sample report

Typical of team or organisation apps generated by Lovable or Bolt: a policy on members checks membership by selecting from members, which triggers the same policy again.

Where it breaks

SELECT membersfrom your appPolicy on memberssubquery on membersReads memberspolicy runs againFix: functionsecurity definerchecksqueriesitselfreplacewithSELECT membersfrom your appPolicy on memberssubquery on membersReads memberspolicy runs againFix: functionsecurity definerchecksqueries itselfreplace with
The policy on members reads members, which triggers the same policy again. A SECURITY DEFINER function breaks the loop.

Which case is yours?

  1. A policy on table A queries table A (directly or through table B whose policy queries A). Postgres evaluates the policy for the subquery too and loops.

The fix, step by step

  1. Move the membership lookup into a SECURITY DEFINER function. It runs with the owner's rights, so RLS is not evaluated again inside it.
    create or replace function public.is_member(org uuid)
    returns boolean language sql security definer stable
    set search_path = public as $$
      select exists (
        select 1 from members
        where org_id = org and user_id = auth.uid()
      );
    $$;
    
    revoke execute on function public.is_member(uuid) from anon;
  2. Rewrite the policies to call the function instead of the subquery.
    drop policy if exists "members can read" on members;
    create policy "members can read" on members
      for select to authenticated using (public.is_member(org_id));
  3. Keep the function in a schema the API does not expose if it returns anything sensitive, and always pin search_path as above.

How to check it is fixed

Run the app as a member and as a non-member: the member sees the team, the non-member gets zero rows, and the recursion error is gone from the Postgres logs.

Delivery example for this error

policies.sql · on a branch of your repository- using (org_id in (select ...))+ using (public.is_member(org_id))+ -- security definer function
Verification checklist in the note
  • Root cause: A policy on a table queries that same table (directly or through another one), so Postgres evaluates the policy again and loops.
  • Change made: Move the membership lookup into a SECURITY DEFINER function with a pinned search_path and call it from the policies.
  • Run the app as a member and as a non-member: the member sees the team, the non-member gets zero rows, and the recursion error is gone from the Postgres logs.

Illustrative: the real diff is written against your repository. Full sample report

Still stuck on your own code?

Send the repository and the exact error. Fix: 290 EUR all taxes included, delivered within 72 hours, refunded if not resolved.

Private repository: paste its link anyway, we reply by email within one business day with the GitHub account to invite with read access. A zip link (Google Drive, Dropbox) works too. Never send passwords or secret keys in this form.

Fix: One blocking auth, Supabase RLS or deployment problem fixed in your repository.290 EUR all taxes included · 72 hours

Secure payment by Stripe. Not resolved within 72 hours: refunded in full.

Not sure it is this error? Ask for a free written diagnosis, no card needed.