RLS policy causes infinite recursion #47525
Replies: 2 comments
-
|
Hello everyone, im fully active now, please let's sort things out. |
Beta Was this translation helpful? Give feedback.
-
|
The article describes the problem well. Here are the three patterns that fix it in practice. Pattern 1. Use auth.uid() directly instead of querying another table. Instead of checking a roles table inside your policy: CREATE POLICY bad_policy ON documents FOR SELECT Check the JWT claims if you store the role there: CREATE POLICY good_policy ON documents FOR SELECT Pattern 2. Create a SECURITY DEFINER helper function. CREATE OR REPLACE FUNCTION public.current_user_role() CREATE POLICY role_policy ON documents FOR SELECT The SECURITY DEFINER function runs as the owner and bypasses RLS on user_roles, breaking the cycle. Pattern 3. Grant the anon and authenticated roles SELECT on the lookup table and disable RLS on it, since the table contains no sensitive per-user data. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
This is a copy of a troubleshooting article on Supabase's docs site. It may be missing some details from the original. View the original article.
If your Storage or database requests encounter an error and the corresponding Postgres logs show 'infinite recursion detected in policy for relation "table_name"', it is because of infinite recursion in your Row-Level Security (RLS) policies.
Why Does This Happen?
This error indicates a circular dependency between RLS policies. It occurs when an RLS policy queries a table with RLS enabled, and that table's policies end up triggering the original policy again.
This can happen when:
Postgres detects the recursive policy evaluation and terminates the query to prevent infinite recursion. This error can also occur during Storage operations if a Storage RLS policy references a table with self-referencing or mutually recursive RLS policies.
How to Resolve This Issue:
Option 1: Update the table's RLS policies to ensure they do not directly or indirectly create a circular dependency.
Option 2: Wrap the permission check in a SECURITY DEFINER function. This executes with the privileges of the user who created the function — if created with a role like postgres, it bypasses RLS on the target table and breaks the recursion. See Use Security Definer Functions for details.
Beta Was this translation helpful? Give feedback.
All reactions