Supabase breaking changes, updated weekly
Every verified Supabase trap in Footgun: changes and behaviors that break code or give wrong results, newest first. Each one has the error you see, the fix, and the date it was last checked. The list updates when the weekly check adds or retires a trap. For the full cause and sources, open the trap, or see all Supabase traps.
fg-0570· added 2026-10-27· last checked 2026-10-27
Anyone with your Supabase publishable or anon key can read and write a table that has RLS off
Symptom
Rows can be read through the Data API with only the project URL and the publishable or anon key, no sign-in
Fix
Enable RLS on every table in an exposed schema, then add policies for exactly the access each role needs. Once RLS is on, the publishable key reaches no rows until a policy allows it, so write the policies before your app relies on the table.
fg-0571· added 2026-10-27· last checked 2026-10-27
Files in a public Supabase Storage bucket can be downloaded by anyone who has the URL
Symptom
A file URL opens in a private browser window with no sign-in
Fix
Keep private user files in a private bucket and serve them with short-lived signed URLs created on the server, or with an authenticated request that carries the user's token. Use public buckets only for files anyone may see, such as avatars or marketing images.
fg-0569· added 2026-10-27· last checked 2026-10-27· deadline 2026-12-31
A Supabase service_role or secret key in browser code lets anyone skip every RLS policy
Symptom
The service_role key or an sb_secret_ key is set in a NEXT_PUBLIC_ variable or passed to createClient in a client component
Fix
Use only the publishable key (or the legacy anon key) in browser and mobile code, and keep secret keys in server-only environment variables without the NEXT_PUBLIC_ prefix. If a secret key was ever shipped or committed, fix the cause of the leak first, then create a new secret key, replace it everywhere, confirm every component uses it, and delete the old one.
fg-0196· added 2026-10-15· last checked 2026-10-15
prepared statement already exists errors when connecting to Supabase through the pooler on port 6543
Symptom
prepared statement "s0" already exists
Fix
Turn off prepared statements in the driver when using port 6543, or use session mode or a direct connection for code that needs them, including migrations.
fg-0203· added 2026-10-15· last checked 2026-10-15
Supabase Realtime postgres_changes subscription says SUBSCRIBED but never receives any events
Symptom
Channel status SUBSCRIBED, then silence when rows change
Fix
Add the table to the publication, confirm the subscriber can select the changed row, and set replica identity full if you need old values on tables without RLS.
fg-0205· added 2026-10-15· last checked 2026-10-15
Supabase signUp fails with Database error saving new user after adding a profiles trigger
Symptom
AuthApiError: Database error saving new user (500, unexpected_failure)
Fix
Declare the function security definer with search_path set to empty, fully qualify every table, make inserted columns nullable or defaulted, and read the real error in the Auth and Postgres logs.
fg-0206· added 2026-10-15· last checked 2026-10-15
Supabase Storage upload fails with 403 new row violates row-level security policy despite an INSERT policy
Symptom
StorageApiError: new row violates row-level security policy (403)
Fix
Add SELECT (and UPDATE if you overwrite) policies on storage.objects that mirror the INSERT policy's bucket and path checks.
fg-0202· added 2026-10-15· last checked 2026-10-15
Supabase queries hang forever after awaiting a Supabase call inside onAuthStateChange
Symptom
The next supabase.from(...) or getSession() anywhere in the app never resolves, with no error
Fix
Upgrade to supabase-js 2.107.0 or later. On older versions keep the callback synchronous and defer any Supabase call with setTimeout. Even on new versions, never call refreshSession from a TOKEN_REFRESHED handler.
fg-0199· added 2026-10-15· last checked 2026-10-15
Supabase client created with the service role key still gets RLS errors or empty results
Symptom
new row violates row-level security policy from a client built with the service_role or sb_secret key
Fix
Build a separate admin client with plain createClient, no cookies, and session persistence off. Create users with auth.admin.createUser rather than signUp on that client.
fg-0195· added 2026-10-15· last checked 2026-10-15
Connecting to the Supabase database from Vercel or GitHub Actions fails with ENETUNREACH
Symptom
connect ENETUNREACH 2a05:... :5432
Fix
Use the pooler connection string (transaction mode on port 6543 for serverless, session mode on 5432 for long-lived servers), or buy the dedicated IPv4 add-on on Pro and above.
fg-0197· added 2026-10-15· last checked 2026-10-15
Server logs fill with Using the user object as returned from supabase.auth.getSession() could be insecure
Symptom
Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure
Fix
Use getClaims() to verify the JWT, or getUser() to ask the Auth server, whenever an identity decision is made on the server. Read only the access token from getSession, never the user object.
fg-0198· added 2026-10-15· last checked 2026-10-15
Supabase Auth confirmation and magic link emails fail with Email address not authorized or hit a rate limit
Symptom
Email address not authorized when signing up anyone outside the project team
Fix
Configure a custom SMTP provider before launch, then raise the email rate limit on the Auth rate limits page to match expected signups.
fg-0253· added 2026-10-15· last checked 2026-10-15
Supabase Edge Function returns 401 Invalid JWT for signed-in users after switching to asymmetric JWT signing keys
Symptom
{"code":401,"message":"Invalid JWT"} when the client sends a logged-in user's access token
Fix
Turn off verify_jwt for the function and authenticate inside the handler, for example with getClaims on a client built from the request's Authorization header, or with the @supabase/server SDK.
fg-0201· added 2026-10-15· last checked 2026-10-15
Supabase OAuth or magic link ignores redirectTo and sends users to localhost or the Site URL
Symptom
After Google sign-in the browser lands on http://localhost:3000 in production
Fix
Add every production, preview, and local callback URL to the allow list, using wildcards for preview domains, and set Site URL to production.
fg-0204· added 2026-10-15· last checked 2026-10-15
Supabase select returns an empty array with no error even though the table has rows
Symptom
{ data: [], error: null } for a table that has data in the Table Editor
Fix
Add a SELECT policy for the role that actually makes the call, and confirm a user JWT is attached at call time by checking auth.jwt() through an RPC.
fg-0207· added 2026-10-15· last checked 2026-10-15
Supabase update returns no error but changes nothing because the table has no SELECT policy
Symptom
update() resolves with error null and status 204 while the row is unchanged
Fix
Add a SELECT policy covering the same rows as the UPDATE policy, and chain .select() in tests so a zero-row update is visible.
Have your agent check Supabase changes before it codes