Step-by-step guides for the most common Lovable problems, written by real developers.
Stripe webhook endpoint receives events but signature verification fails. Webhook handler rejects legitimate events. Payment events aren't processed correctly. Security validation throws errors.
Stripe signs webhooks with your endpoint secret. Verification ensures events are authentic and haven't been tampered with. Signature mismatch indicates wrong secret or data corruption.
Edge functions work in production but hard to test locally. Need to deploy to test. No local execution environment. Debugging is difficult without local testing.
Supabase CLI provides local development environment for testing functions before pushing to production.
Test payments work but production payments fail. Using test keys in production or live keys in development. Webhooks not firing in right environment. Keys mixed up causing transaction failures.
Stripe has separate test and live environments with different keys. Mixing keys between environments breaks payment flow.
Edge function requests timeout after 120 seconds with 504 Gateway Timeout. Function doesn't execute or returns 500 error. Async operations timeout. Functions work locally but fail in production.
Supabase Edge Functions have strict timeout limits and require optimization for fast execution. Network calls and database queries must complete quickly.
Webhook endpoint configured in Supabase but never receives events. Database changes occur but webhook isn't triggered. Endpoint appears to work when tested but events don't arrive.
Webhooks require proper table configuration, filter setup, and endpoint accessibility. Events must be published and delivered correctly.
Calling third-party APIs from React app fails with CORS error. 'Access-Control-Allow-Origin' header missing. Works in backend but not client-side. Browser blocks cross-origin request.
CORS restrictions prevent client-side code from calling arbitrary APIs unless the API explicitly allows it. Solution requires using backend proxy or Edge Functions.
Database queries fail with 'new row violates row-level security policy' or 'permission denied' errors. Users cannot read or write to tables despite having authentication credentials.
This occurs when RLS policies are too restrictive or missing entirely. RLS must be explicitly enabled per table and policies must allow the current auth context.
Supabase anon key is visible in browser. Someone could copy it and use it to call Supabase API directly. Key is committed to Git. Security concern: data exposed via anon key.
Anon keys must be exposed on client but should never have direct table access. RLS policies protect data from unauthorized access even with key.
User logs in successfully but gets redirected to login page again. Auth state is lost after clicking a link or navigating. Session appears to end prematurely during redirect flow.
Auth state must persist during navigation. If state isn't properly restored from storage before redirect, users see login page again.
Need to perform operations that bypass RLS for server-side actions. Can't use regular client for certain admin operations. RLS blocking necessary backend logic.
Supabase admin client uses service role key which bypasses RLS. Use only in secure backend environment, never expose service role key to client.
OAuth authentication fails with error 'redirect_uri_mismatch' or callback page shows blank/error. Users cannot sign in via GitHub or Google because the configured redirect URL doesn't match.
OAuth providers validate that the redirect URL matches exactly what was registered. Any difference in protocol, domain, path, or query parameters will cause the mismatch error.
Users experience sudden logout after being idle or when making requests. API calls start failing with 401 Unauthorized. The JWT token has expired but the app didn't refresh it before it became invalid.
By default, Supabase tokens expire after 1 hour. Without proper refresh token handling, expired tokens cause failures silently rather than triggering re-authentication flow.
After authenticating with Supabase, the user session disappears when the page is refreshed. Users are logged out unexpectedly, and the authentication state is not being maintained across browser sessions.
This typically happens because the auth session data is stored in memory only, rather than being persisted to localStorage or sessionStorage. When the page reloads, the in-memory state is lost.
Realtime subscriptions are set up but changes made by other users or external updates are not reflected in the UI. The app shows stale data even though data changed in the database.
Realtime requires explicit table replication configuration. Many tables have realtime disabled by default. Subscriptions also need to be set up before the page loads.
When users submit forms or interact with the app, data appears to save locally but never reaches the database. Supabase inserts and updates silently fail without throwing errors. Data is lost on page reload.
This typically happens when insert/update operations fail due to RLS policies, missing required fields, type mismatches, or unhandled promise rejections.
Deployment fails because database migrations encounter errors. Schema changes conflict with existing data or migrations are applied in wrong order. Database becomes in inconsistent state, blocking the deployment.
Migrations must be designed carefully to handle existing data without data loss. Supabase maintains migration history and applies them sequentially.
Attempting to delete or update records fails with 'foreign key constraint violation'. Child records reference the record being deleted, preventing the operation. This breaks the intended delete flow.
Foreign keys enforce referential integrity. When records are related, the database prevents orphaned references unless cascade rules are configured.
App performance degrades as data grows. Loading 100 items runs 101 queries (1 for items + 1 per item for related data). Database becomes bottleneck with high latency and connection pool exhaustion.
N+1 occurs when fetching parent records, then looping to fetch each child separately, instead of joining in single query.
Querying JSON columns returns no results or errors. Filter on nested JSON properties doesn't work. JSONB operators don't execute correctly.
PostgreSQL JSONB requires specific operators and syntax. Regular comparison doesn't work on JSON fields.
Requests start failing with 'too many connections' or connection timeout errors. Error appears after app runs for a while or under load. Connection pool is exhausted.
Database has limited connections. Without proper connection management, connections leak and pool becomes exhausted.
Users can read data from table but cannot insert or update. 'permission denied' error on insert/update despite having select access. RLS policies inconsistently applied across operations.
Each database operation (SELECT, INSERT, UPDATE, DELETE) needs its own RLS policy. Common mistake is creating only SELECT policy and assuming others inherit.
API keys and configuration values are undefined in production. Supabase URL and API key return undefined, causing all API calls to fail. Works locally with .env.local but not in production.
Vite only exposes variables prefixed with VITE_ to the client. Production requires proper build-time or runtime environment setup.
API requests to Supabase fail with CORS error in production. 'Access-Control-Allow-Origin' header missing or not matching domain. Works locally but fails on deployed site.
CORS policy requires server to explicitly allow requests from client domain. Browser blocks cross-origin requests without proper headers.
App works perfectly in development (npm run dev) but production build shows blank page (npm run build). No errors in console. Static assets fail to load with 404. JavaScript doesn't execute.
Production builds use optimized bundling that can expose issues hidden in dev mode. Base path, asset references, and build configuration mismatches cause blank pages.
Vite dev server starts but HMR connection fails with 'WebSocket connection failed' or 'net::ERR_CONNECTION_REFUSED'. Changes require manual page refresh instead of hot reload. Development experience is slow.
HMR requires WebSocket connection from browser to dev server. Network configuration or firewall can block the connection.
File upload to Supabase Storage fails with CORS error. 'Access-Control-Allow-Origin' missing in response. Works with API key but not with RLS. Uploads blocked from production domain.
Supabase Storage requires CORS configuration and proper bucket settings for client-side uploads.
Features requiring HTTPS (geolocation, service workers, secure cookies) don't work on localhost:5173. Browser blocks insecure context APIs. Need to test HTTPS-only features in development.
Development typically uses HTTP, but some APIs require HTTPS. Self-signed certificates enable local HTTPS testing.
Import aliases work in development (@/components) but fail in production build. Build fails with 'cannot find module' errors. Aliases not recognized by TypeScript or bundler.
Vite aliases require configuration in both vite.config.js and tsconfig.json. Missing either causes resolution failures.
Users don't see app updates. Old JavaScript cached in browser. New features don't appear even after deployment. Cache headers prevent fresh content.
Browser caches static assets for performance. Without proper cache headers, users see stale code.
Styled-components, Emotion, or other CSS-in-JS works in dev but fails in production build. Styles disappear or don't apply. Class names don't match between server and client.
CSS-in-JS requires proper build configuration for server-side rendering and style extraction.
App memory usage grows over time. Performance degrades after extended use. DevTools memory profiler shows detached DOM nodes and event listeners. Browser tab becomes unresponsive.
Event listeners and subscriptions must be cleaned up when components unmount. Not removing them causes memory to accumulate.
First call to Edge function is slow (2-5 seconds). Subsequent calls are fast. Cold start is noticeable for users. Function invocation time is unpredictable.
Serverless functions have cold start delay when first deployed or after inactivity. Function container spins up and loads dependencies.
App takes 5+ seconds to load initial page. Blank white screen for extended period. Users see slow Time to First Contentful Paint (FCP) and Time to Interactive (TTI). Performance metrics are poor.
Page load speed depends on bundle size, network latency, and resource blocking. Optimizations include code splitting, lazy loading, and resource prioritization.
Coming from Next.js Image component, Vite React app loads unoptimized images. No automatic responsive images or lazy loading. Performance metrics show large image bytes.
Vite doesn't provide built-in image optimization like Next.js. Manual optimization or third-party tools needed.
App performance noticeably slower with console.log in render. Removing logs makes app faster. Lots of logging output in DevTools console. Re-renders feel sluggish.
Console.log in render code executes on every render. Heavy logging causes measurable performance hit, especially during scrolling or animations.
Images are loading large uncompressed files (5MB+). Page load is slow because image downloads are slow. High resolution images used even on mobile. No lazy loading.
Web images need optimization for format, size, and lazy loading. Unoptimized images account for >50% of page weight in many sites.
React components render on every state change even when their props don't change. Performance degrades with large lists. User interactions lag. DevTools Profiler shows excessive renders.
React re-renders components when props or state change. Unnecessary renders occur when parent state updates but child doesn't need the new data.
Zustand state changes in store but components don't re-render. Updates work in other components but not in specific one. Selector hook returns stale data.
Zustand uses selector pattern to optimize re-renders. Improper selectors or store structure can cause missed updates.
Browser becomes unresponsive. useEffect runs infinitely, making thousands of API calls. Network tab shows repeated requests. Browser memory increases until crash.
Infinite loops occur when dependency array is missing or incorrect, causing effect to run on every render, which updates state, causing re-render, repeating infinitely.
useContext() hook returns undefined even though context is defined. 'Cannot read property of undefined' errors when accessing context value. Context hook used outside provider scope.
Context consumers must be wrapped in their provider component. Using context outside provider scope or with missing provider returns undefined.
Dark mode toggle doesn't work or resets on page reload. Classes like 'dark:bg-gray-900' don't apply when dark mode is enabled. Theme preference not saved.
Dark mode requires class management on root element and localStorage persistence. Tailwind dark mode has multiple strategy options.
Clicking submit button multiple times creates duplicate records. Data submitted in wrong order due to async operations completing out of sequence. UI doesn't disable button during submission, causing race conditions.
Async form submissions need proper loading state to prevent duplicate submissions. Promises can resolve in any order, creating data inconsistencies.
Tailwind classes are written correctly but styles don't apply to elements. Custom CSS conflicts with Tailwind. Class purging removes needed styles or adds unwanted ones.
Tailwind requires proper configuration of content paths for class scanning. Conflicts occur when CSS specificity issues override Tailwind utilities.
Strict mode enabled but type errors prevent build. 'Cannot assign type' and 'missing type' errors. Null/undefined safety enforced. Code works but TypeScript won't compile.
Strict mode enforces stricter type checking. Requires more explicit typing but catches bugs early.
Single component error crashes entire app. White screen or error overlay shown to users. No graceful error handling. Error in child component propagates up.
React Error Boundaries catch errors in component trees. Prevents entire app from crashing due to single component error.
Changes to tailwind.config.js don't appear in development. Need to restart dev server to see theme changes. New colors, spacing, or custom utilities don't apply.
Vite should watch tailwind.config.js but sometimes changes aren't detected. Manual server restart required.
App looks perfect on desktop but mobile screens show broken layout - text overlaps, buttons are cut off, content is unreadable. Horizontal scrolling required. Tailwind classes not applying correctly at smaller breakpoints.
Mobile responsiveness requires testing at actual mobile sizes and using Tailwind breakpoint prefixes (sm, md, lg) to adapt layout.
Warning: 'Each child in a list should have a unique key prop' when using fragments. Can't add key to <> syntax. Lists don't render correctly with fragment groups.
Fragments in lists need keys when rendering multiple elements per item. Shorthand <> syntax doesn't support keys.
Console warning: 'Each child in a list should have a unique key prop'. List re-renders cause wrong components to update. List items in wrong order after dynamic changes.
React uses keys to identify list items. Without unique keys, React reuses component instances incorrectly.
ESLint shows 'missing dependency in useEffect' or 'exhaustive-deps' warning. Code works but warning suggests adding dependencies. Adding dependencies causes infinite loops. Stale closures reference old values.
React hooks require explicit dependency arrays to track when effects should re-run. Missing dependencies cause stale closures; extra ones cause infinite loops.
Modal dialog stays open after clicking close button or outside. Multiple modals stack without closing previous ones. Backdrop remains visible even when modal closes. Z-index issues cause modals to appear behind other content.
Modal state must be properly managed with React state and backdrop click handlers. CSS z-index requires careful layering.
Styles can't be overridden despite being written after conflicting rules. !important needed everywhere. Third-party styles override custom styles. CSS cascade not working as expected.
CSS specificity determines which rule applies when conflicts occur. Higher specificity always wins. Understanding selector specificity is essential.
Form inputs don't update as user types. Values appear frozen. Submitted data shows old/stale values. Controlled inputs and state are out of sync.
React forms require proper state binding with onChange handlers and defaultValue or value props to keep inputs and state synchronized.
You don't need to be technical. Just describe what's wrong and a verified developer will handle the rest.
Get Help