afterbuild/ops
ERR-815/Lovable · production failure
ERR-815
Why is my Lovable app broken?

appears when:After the Lovable preview is published to a production domain and real users start hitting the app

Why is my Lovable app broken? The 5 most common failures (2026)

The Lovable preview hides your Supabase URL, your permissive policies, and your OAuth callbacks. Production hides none of that. Five configuration seams account for almost every panic call we take.

Last updated 17 April 2026 · 12 min read · By Hyder Shah
Direct answer
Your Lovable app is broken because production surfaces at least one configuration seam that the Lovable preview hides. In order of frequency: (1) environment variables didn’t follow you to the host, (2) Supabase Row-Level Security is disabled or missing policies, (3) OAuth redirect URLs still reference localhost or the Lovable preview domain, (4) the Stripe webhook is registered against the preview URL with a test-mode secret, and (5) Supabase Edge Functions reject real browsers because CORS is wide open or missing entirely. Identify which seam you’re on using the console error string, then jump to the matching step below.

Quick fix for broken Lovable app

60-second triage: open your production site in an incognito window, open DevTools, and reload. Three windows tell you almost everything.

  1. Console — if the first error is supabaseUrl is required, you have missing env vars. Skip to Step 1.
  2. Network tab — filter for fetch/XHR. A 401 or 403 on a PostgREST call (URL contains /rest/v1/) points at RLS. A CORS badge on a /functions/v1/ call is Edge Function CORS.
  3. Application → Cookies — no sb-access-token after login means OAuth redirect is broken. Check for a localhost in the URL bar after sign-in.

If none of those match, the remaining failure is almost always Stripe — checkout succeeded but the webhook never activated the plan. Jump to Step 4 and check Stripe Dashboard → Developers → Webhooks → recent deliveries.

Deeper fixes when the quick fix fails

01 · Env vars — the actual failure mode, with the log line

The error you will see in the production console on first load is almost always this exact string:

browser / build output
bash
01# Browser console after production deploy02Uncaught Error: supabaseUrl is required.03    at new SupabaseClient (supabase-js.mjs:??)04    at createClient (supabase.ts:3)05    at <anonymous> (layout.tsx:12)06 07# Or on Vite builds:08[vite:define] Could not resolve import.meta.env.VITE_SUPABASE_URL09error during build:10Error: Missing required env var VITE_SUPABASE_URL
If either of these lines appears, the variable is undefined in the bundle. Fix in the host's env panel, NOT in the Lovable panel.

02 · Env vars — the copy-paste fix

List every key Lovable set, then mirror them to the host. Keep build-time variables (NEXT_PUBLIC_*, VITE_*) on a separate line — they bake into the bundle and need a fresh deploy to take effect. Deeper dive at env variables not loading on Vercel.

.env.production (reference)
bash
01# Required by every Lovable + Supabase app02NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co03NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOi...04SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOi...    # server-only, NEVER NEXT_PUBLIC_05 06# If the app uses Stripe07STRIPE_SECRET_KEY=sk_live_...               # live, not sk_test_08STRIPE_WEBHOOK_SECRET=whsec_...             # the live-mode endpoint's secret09 10# If OAuth is enabled11NEXT_PUBLIC_SITE_URL=https://yourapp.com    # must be your real domain
After pasting into Vercel / Netlify env and redeploying, reload in incognito. The 'supabaseUrl is required' error should be gone.

03 · RLS — the log line that tells you the database is actually deny-all

Supabase Dashboard → Logs → Postgres Logs. Filter ERROR. You are looking for one of these two lines after a failed INSERT or SELECT:

Supabase → Logs → Postgres
sql
01-- The explicit deny02ERROR: new row violates row-level security policy for table "tasks"03  STATE: 4250104 05-- The silent deny (read side)06-- Client sees: HTTP 200 OK with []07-- Postgres log shows the query ran but no rows matched any SELECT policy08 09-- The worst one: RLS disabled entirely10WARNING: RLS is disabled on table "tasks"11  Rows are visible to every role including anon.
The third variant is the one that ships PII. Treat RLS-disabled as a production incident.

04 · RLS — the minimum correct policy

The copy-paste fix for single-tenant ownership. Every table with user data needs all four policies (SELECT, INSERT, UPDATE, DELETE) scoped to authenticated, not publicpublic includes anon. For the tool-agnostic deep dive see Supabase RLS blocking insert.

supabase/migrations/<timestamp>_rls_tasks.sql
sql
01-- Enable RLS02alter table public.tasks enable row level security;03 04-- SELECT: see your own rows05create policy "tasks_select_own" on public.tasks06  for select to authenticated07  using (auth.uid() = user_id);08 09-- INSERT: write rows owned by you10create policy "tasks_insert_own" on public.tasks11  for insert to authenticated12  with check (auth.uid() = user_id);13 14-- UPDATE: modify your own rows15create policy "tasks_update_own" on public.tasks16  for update to authenticated17  using (auth.uid() = user_id)18  with check (auth.uid() = user_id);19 20-- DELETE: remove your own rows21create policy "tasks_delete_own" on public.tasks22  for delete to authenticated23  using (auth.uid() = user_id);24 25-- Default the ownership column so clients cannot forget it26alter table public.tasks27  alter column user_id set default auth.uid();
Verify with two real user accounts in two incognito windows. If user A sees user B's rows, you wrote a bad policy.

05 · OAuth — the error string in the URL bar

If you’re bouncing back to the login page after a successful Google sign-in, inspect the URL bar during the redirect. You will see one of these. The tool-agnostic fix is OAuth callback URL not working in production.

browser URL bar during OAuth redirect
bash
01# Google's own error (most common)02https://accounts.google.com/signin/oauth/error/v2?03  authError=...&error=redirect_uri_mismatch04 05# Supabase rejects the callback06https://yourapp.com/?error=invalid_request07  &error_description=Redirect+URL+is+not+allowed08 09# Session disappears after redirect10# URL is correct but application cookies are empty:11# Missing: sb-access-token, sb-refresh-token12# Cause: Site URL still points at the preview domain
Google's error_description is always literal. Copy it verbatim and match to the Google Cloud Console allowed URIs list.

06 · OAuth — fix Supabase Site URL and Google OAuth client

Both sides must agree on the production domain. The order matters: fix Supabase first so the token exchange lands, then fix Google so the consent step accepts the redirect.

  1. Supabase Dashboard → Authentication → URL Configuration. Set Site URL to https://yourapp.com. Add https://yourapp.com/** to Additional Redirect URLs.
  2. Google Cloud Console → APIs & Services → Credentials → OAuth 2.0 Client. Add your Supabase callback to Authorized Redirect URIs: https://<project-ref>.supabase.co/auth/v1/callback. Also add https://yourapp.com to Authorized JavaScript Origins.
  3. Test in a fresh incognito window. Sign in with Google. Confirm the session cookie sb-access-token is set on your domain, not on *.lovable.app.

07 · Stripe — the dashboard tells you which of three it is

Stripe Dashboard → Developers → Webhooks → your endpoint → Recent deliveries. Each failed attempt shows the exact response your server sent.

  • 404 Not Found— wrong URL. The endpoint registered in Stripe does not exist on your production host. Fix: register the correct URL or move the route file to the expected path.
  • 400 No signatures found matching the expected signature— raw-body parsing. Your framework parsed JSON before constructEvent() could verify. Fix: await req.text(), not await req.json(). Deep dive: Stripe webhook not firing.
  • No deliveries at all— test-mode / live-mode mismatch. The webhook exists in test mode only; live events never reach it. Fix: toggle the dashboard to Live and add a second endpoint with a whsec_live_ secret. Tool-specific variant: Stripe stuck in test mode in production.

Lovable-specific gotcha: Lovable’s Supabase Edge Function template runs on the Deno runtime, which serves application/json request bodies differently from Node. The same route handler that works locally under next dev can fail signature verification under a deployed Edge Function because the body arrives pre-decoded. Move the webhook to a Node route if you see signature failures only in production.

08 · CORS — the Edge Function has to handle OPTIONS itself

Supabase Edge Functions don’t inject CORS headers automatically. If you call a function from the browser and see blocked by CORS policy, the function either didn’t handle the OPTIONS preflight or is responding with the wrong origin. Add a shared helper and import it into every function. Broader pattern at CORS error in production only.

supabase/functions/_shared/cors.ts
typescript
01// supabase/functions/_shared/cors.ts02export const corsHeaders = {03  "Access-Control-Allow-Origin": "https://yourapp.com",04  "Access-Control-Allow-Headers":05    "authorization, x-client-info, apikey, content-type",06  "Access-Control-Allow-Methods": "POST, GET, OPTIONS",07  // NEVER use "*" if you send credentials (cookies, Authorization)08};09 10// supabase/functions/my-fn/index.ts11import { corsHeaders } from "../_shared/cors.ts";12 13Deno.serve(async (req) => {14  if (req.method === "OPTIONS") {15    return new Response("ok", { headers: corsHeaders });16  }17 18  // ... your handler ...19  return new Response(JSON.stringify({ ok: true }), {20    headers: { ...corsHeaders, "Content-Type": "application/json" },21  });22});
Re-deploy with `supabase functions deploy <name>`. Verify the OPTIONS response in DevTools → Network → your function call → Response Headers.

09 · DIY vs. rescue — a practical decision matrix

Which path is right depends on how long you’ve been stuck and how much revenue is at risk. Rough guide:

PathProsConsBest when
DIY the 5-step fixFree. You learn your own stack. Full control.Easy to miss a second seam. High risk of regressions on auth and RLS.Pre-launch. No paying users. You have a full evening.
Free diagnosticSecond opinion in 30 minutes. No commitment. Written findings.Async turnaround, not same-day. Not a fix.Stuck 2+ hours and unsure whether the bug is env, RLS, or Stripe.
Emergency Triage · $29948-hour fixed price. Root-cause report. Single bug gone.Scoped to one issue; multi-issue rescues need a larger package.Paying users affected right now, one clear symptom.
Deploy-to-Production Pass · $1,999All five seams closed at once. CI, monitoring, rollback plan included.7-day window. Requires repo and host access.Pre-launch and you want to do it once, correctly.

Also see the outcome-framed engagement pages: Fix my AI app, Add payments to AI app, and Fix broken auth. For the tool-agnostic deep dives on individual errors, see the /fix/ pages linked from each step above.

Why AI-built apps hit broken Lovable app

The causal chain almost always runs the same way. Lovable generates a working preview because it has full control of the sandbox — it provisions a Supabase project, writes the tables, injects a service-role key into every server call, and bakes preview-domain URLs into OAuth and Stripe config. Every database query runs as service_role, which bypasses Row-Level Security entirely, so the model never observes the feedback signal that policies are missing. Every OAuth callback lands at a Lovable-owned URL, so the model never writes the production redirect whitelist. Every Stripe webhook is the one Lovable registered during onboarding in test mode.

At deploy the founder points a custom domain at Vercel or Netlify and copies the Supabase credentials from a Lovable panel into the host’s environment variables. Usually some get missed. The anon key might carry over but the service-role key stays behind; the NEXT_PUBLIC_SUPABASE_URL is typed by hand and has a trailing slash; STRIPE_WEBHOOK_SECRET was never in Lovable to begin with because Lovable pointed the webhook at itself. The client bundle now ships with undefined for half its secrets and silently crashes on first mount.

Even when the env is correct, the database-level config still leaks. Supabase tables created by Lovable almost always ship with RLS off or with a single permissive FOR ALL USING (true)policy that does nothing. Supabase’s own docs make RLS opt-in for compatibility reasons; the model’s training data biases strongly toward enabling RLS only when the founder asks. Nobody asks in a preview because everything works. The production anon key hits the same tables and — depending on whether any policy exists — either fails closed (blank UI, console 401) or fails open (users see each other’s rows). The second outcome is the one that ends up in The Register.

OAuth, Stripe, and CORS follow the same pattern. OAuth works in preview because the Supabase Site URL still points at a Lovable subdomain; the first login on your real domain redirects to that subdomain and loses the session. Stripe webhooks work in preview because the test-mode endpoint is the one Lovable wired up; the first live checkout on your domain has no matching endpoint and the subscription never activates. CORS works in preview because every request is same-origin; the first cross-origin call from your frontend to a Supabase Edge Function returns preflight failure because the function never wrote an Access-Control-Allow-Origin header.

You will have a bug. Now the Disaster begins.
Trustpilot Lovable reviewer

Diagnose broken Lovable app by failure mode

Open DevTools → Console and match your error to a row.

SymptomConsole / log signatureRoot causeFix section
Blank page on load, white screenUncaught Error: supabaseUrl is required.Env vars missing in production bundleStep 1
Signed-in user sees other users' rows200 OK on /rest/v1/<table>?select=* with too many rowsRLS disabled or FOR ALL USING (true) policyStep 2
Login redirects to localhost or .lovable.appredirect_uri_mismatch in URL bar after Google sign-inSupabase Site URL + Google OAuth client still previewStep 3
Checkout succeeds, plan never activatesStripe Dashboard shows webhook 404 or no delivery at allWebhook endpoint wrong or test-mode secret in prodStep 4
Edge Function call returns CORS errorAccess to fetch at '…/functions/v1/…' blocked by CORS policyEdge Function missing OPTIONS handler and CORS headersStep 5

broken Lovable app by AI builder

How often each AI builder ships this error and the pattern that produces it.

AI builder × broken Lovable app
BuilderFrequencyPattern
LovableEvery production deployPreview uses service_role; RLS off by default; webhook wired to preview subdomain
Bolt.newEvery StackBlitz exportWebContainer-only storage vanishes on deploy; webhook URL still stackblitz.io
v0CommonNo backend scaffolded; founder bolts Supabase on later without RLS audit
CursorSometimesFixes regress working code; no CI so RLS policies drift between branches
ReplitCommonReplit-hosted preview swaps secrets behind the scenes; real host sees undefined

Related errors we fix

Stop broken Lovable app recurring in AI-built apps

Still stuck with broken Lovable app?

Emergency triage · $299 · 48h turnaround
We restore service and write the root-cause report.

Five patterns cover the vast majority of broken Lovable apps. If yours is the rare outlier, we’ll find it on the free diagnostic.

  • Stuck for more than 4 hours
  • Paying users affected right now
  • Tried two fixes, broke a third thing
start the triage →

broken Lovable app questions

My Lovable app was working yesterday and now it's broken. What changed?+
Usually one of three things: a Lovable auto-update touched a file, you redeployed and env vars didn't carry over, or Supabase rotated a key. Check your production build log first, then the Supabase dashboard audit log. If neither shows a change, roll back to the previous Vercel/Netlify deployment. If the issue is a specific error string, look under /fix/ for the tool-agnostic deep dive — for example /fix/500-error-after-deploy or /fix/stripe-webhook-not-firing.
Why does my Lovable app work for me but not other users?+
Almost always RLS. You see your own rows because auth.uid() matches. Other users either see nothing or see each other's data. Enable Row-Level Security on every table and add per-user policies. Test with two accounts in two incognito windows before calling it fixed. See /fix/supabase-rls-blocking-insert for the step-by-step with SQL.
How do I know if it's a Lovable bug or my bug?+
If it works in Lovable's preview but not on your production host, it's your configuration — env vars, RLS, redirects, webhooks, or CORS. If it doesn't work in preview either, check the Lovable status page. Lovable bugs that cross the preview boundary are rare compared to configuration drift. Preview-vs-production disparities are covered in /platforms/lovable-developer/problems/preview-works-prod-broken.
Can I just redeploy to fix a broken Lovable app?+
No. Redeploying with the same configuration reproduces the same break. You need to identify the actual failure (use the console) and change the configuration — env var, RLS policy, redirect URL, webhook URL, or CORS header — before redeploying. Every step in this guide starts with identifying the specific log line so you change the right thing.
How much does it cost to fix a broken Lovable app?+
Our Emergency Triage is $299 fixed price with 48-hour turnaround for a single root cause. A full Deploy-to-Production pass — env, CI/CD, monitoring, rollback plan, error tracking — is $1,999. Hourly freelance rates on Upwork run $50–$150/hour for Lovable-specific work. The outcome-framed commercial page is /solutions/fix-my-ai-app — start there if you're shopping for a paid engagement rather than self-diagnosing.
Is it worth rescuing a broken Lovable app or should I rewrite?+
Rescue if the broken surface is configuration (env, RLS, OAuth, webhooks, CORS) or a single bad component. Rewrite if the whole data model is wrong, RLS can't be retrofitted, or the code is >3,000 lines of AI spaghetti with no tests. We offer a free 30-minute diagnostic call to help you decide. The longer taxonomy of the rescue-vs-rewrite question lives at /stack/rewrite-or-rescue-vibe-coded-app.
Next step

Ship the fix. Keep the fix.

Emergency Triage restores service in 48 hours. Break the Fix Loop rebuilds CI so this error cannot ship again.

About the author

Hyder Shah leads Afterbuild Labs, shipping production rescues for apps built in Lovable, Bolt.new, Cursor, Replit, v0, and Base44. our rescue methodology.

broken Lovable app experts

If this problem keeps coming back, you probably need ongoing expertise in the underlying stack.

Sources