Incident pattern

Lovable app works in preview but API calls fail after publish

Everything works in the Lovable preview, but the published app fails: API calls return 401/403/500, third-party integrations are dead, or features behave as if their API keys vanished.

  • Lovable
  • Checkout & payments
  • Auth & login

Root cause, in plain English

Lovable frontends are Vite builds: only variables prefixed VITE_ are baked into browser code, and they're baked at build time — a key added or changed after your last publish isn't in the published bundle until you publish again. Server-side secrets live separately (Lovable's secrets panel, delivered to Supabase Edge Functions), never reach frontend code, and occasionally need re-saving before a function picks them up.

How to fix it

  1. Decide which side each value belongs on. Anything secret (Stripe secret key, service keys, API tokens with write access) must stay server-side in an Edge Function — a VITE_ variable is publicly readable by anyone who opens devtools.

  2. For frontend config (publishable keys, project URLs): name it with the VITE_ prefix, then publish again. The published bundle only updates on publish.

  3. For server secrets: add them in the secrets panel so they're injected into Edge Functions, and read them with Deno.env.get("NAME") — no prefix.

  4. Check the Edge Function logs for the failing call. "NAME is not defined" or empty-string auth headers confirm the secret isn't reaching the function; deleting and re-adding the secret forces a clean reload.

  5. Re-test the live published URL, not the preview — the two run different builds with different injection paths.

How Nightlamp detects this automatically

  • API canary
  • Browser journey
  • Keyword check

An api_canary calls your published app's API endpoints on a schedule and alerts on the 401/500 burst that follows a publish with missing keys. A browser_journey exercises the real user flow against the published URL — not the preview — and an http_keyword check asserts that pages render fetched data instead of an error state.

Catch this before your customers do

Nightlamp runs these checks continuously against your live app and sends a plain-English diagnosis — not a wall of logs — the moment this pattern shows up.

Frequently asked questions

Why did this work in preview but not after publishing?
Preview and published are separate builds. The preview rebuilds constantly and picks up recent changes; the published bundle is frozen at publish time. Any VITE_ variable changed since your last publish exists in preview but not in production until you publish again.
Is it safe to put my Stripe secret key in a VITE_ variable?
No. Every VITE_ value is compiled into the JavaScript your visitors download — treat it as public. Secret keys belong in Edge Function secrets, with the frontend calling the function rather than Stripe directly.
The secret is saved but the Edge Function still can't read it.
Confirm the exact name matches what the code reads, then delete and re-add the secret and redeploy the function — a stale function environment that hasn't loaded a recently added secret is a known failure mode, and a forced re-save clears it.

Newsletter

Get new incident patterns as we publish them

One email when new failure patterns, fixes, and monitoring recipes for no-code and AI-built apps land. No fluff, unsubscribe any time.

Double opt-in. One-click unsubscribe. No spam, ever.