'Edge Function returned a non-2xx status code' in Supabase and Lovable
Symptoms
- A feature backed by a Supabase Edge Function (AI calls, emails, Stripe webhooks) fails with the toast or console error 'Edge Function returned a non-2xx status code'
- The client error contains zero detail about what actually went wrong
- Lovable's fix attempts loop because it cannot see the real failure
- Lovable's feedback board has a dedicated thread: 'Lovable creates non-working edge functions it cannot fix'
Why it happens
functions-js collapses every failure into one message
The client library surfaces any non-2xx response with this single opaque string, a long-standing complaint tracked in supabase/functions-js issues #51 and #55.
Uncaught exception in the function
An unhandled error crashes the function with a 500 WORKER_ERROR, and the client sees only the generic wrapper.
Missing secret
Deno.env.get() returns undefined when the secret was never set or is named differently than the code expects, and the function dies when it tries to use it.
JWT verification rejecting the call
JWT verification is enabled but the client calls without a valid token, producing a 401.
CORS, wrong URL, or resource limits
Missing CORS headers on the OPTIONS preflight fail browser calls; a wrong function name or URL returns 404; timeouts and resource limits return 546.
How to fix it
- Read the real error in the function logsThe client message is a wrapper; the truth is in the logs. Open the Supabase dashboard > Edge Functions > your function > Logs. In Lovable Cloud projects, look under Cloud > Functions/Logs instead.
- Wrap the handler so future errors are readableIf the log shows an uncaught exception (a 500 WORKER_ERROR), wrap the handler body in try/catch and return new Response(JSON.stringify({ error: message }), { status: 500, headers: corsHeaders }). From then on, failures come back as readable messages instead of the opaque wrapper.
- Fix 401s: pass the JWT or make the endpoint publicA 401 means JWT verification is enabled but the call lacks a valid token. Either pass the user's JWT in the Authorization header from the client, or set verify_jwt = false in the function config. Only disable verification for endpoints that genuinely need no auth.
- Check the secrets by exact nameIf the function dies reading a secret, Deno.env.get() returned undefined. Confirm the secret exists under Edge Functions > Secrets (or Lovable Cloud > Secrets) with the exact name the code reads, then redeploy the function.
- Handle CORS for browser callsRespond to the OPTIONS preflight with Access-Control-Allow-Origin and Access-Control-Allow-Headers, and include the same headers on every response, including error responses. A missing preflight handler kills browser calls before your code even runs.
- Feed Lovable the log lines, and know the redeploy workaroundPaste the exact log lines into Lovable Chat mode and ask it to fix that specific failure; without the logs it loops. If a redeploy mysteriously does not take effect, deploying the function under a new name is a known workaround (supabase/supabase issue #35236).
How to prevent it
- Wrap every edge function handler in try/catch that returns a JSON error with CORS headers.
- Create secrets before deploying code that reads them, with names matching exactly.
- Keep a shared corsHeaders object and apply it to every response, including the OPTIONS preflight.
- When asking the AI to fix a function, always paste the log output, never just the client toast.
Tools that actually fix this
Recommended because they address the failure mode above, not because of the payout. Some are affiliate links; see how we choose.
The default error tracker for JS and Python. It catches the unhandled exceptions and swallowed promise rejections AI-generated code ships with, and gives you the stack trace instead of a mystery.
Try Sentry →Uptime, heartbeat, and log monitoring built for indie devs. Heartbeats catch the dead background job your app never noticed, and log alerts surface the errors it never handled. Real free tier.
Try Better Stack →Frequently asked questions
What does 'Edge Function returned a non-2xx status code' actually mean?
It means your Supabase edge function responded with something other than success, and the functions-js client collapses every such failure into this one generic message, a long-standing complaint tracked in supabase/functions-js issues #51 and #55. The real cause, whether a 500 crash, missing secret, 401 auth failure, CORS rejection, 404 wrong name, or 546 timeout, is only visible in the function's logs. Read the logs before attempting any fix.
Where do I find Supabase edge function logs?
In the Supabase dashboard, open Edge Functions, select your function, and open its Logs view. For Lovable Cloud projects, where the Supabase instance is managed by Lovable, look under Cloud > Functions/Logs instead. The logs show the underlying exception or status code that the client-side 'non-2xx' message hides.
Why does my Supabase edge function return 401?
A 401 means JWT verification is enabled for the function but the request did not carry a valid token. Fix it by passing the user's JWT in the Authorization header from the client, or by setting verify_jwt = false for endpoints that are meant to be public. Do not disable verification on functions that touch user data.
Why does my redeployed edge function still run the old code?
There is a known issue where a Supabase edge function redeploy does not take effect, tracked as supabase/supabase issue #35236. The working workaround is deploying the function under a new name and pointing the client at it. If behavior does not change after a deploy, try that before assuming your fix was wrong.
Sources
- Supabase docs: Edge Functions troubleshooting
- Supabase docs: Edge Function status codes
- Supabase GitHub discussion #30116
- supabase/functions-js issue #51: non-2xx error message
- Lovable feedback board: Lovable creates non-working edge functions it cannot fix
- supabase/supabase issue #35236: redeploy not taking effect
Related errors
Lovable stuck in an error loop: 'Try to Fix' keeps failing
'new row violates row-level security policy' in Supabase (403 / error 42501)
Lovable API key exposed: secrets visible in your client-side code
v0 environment variables undefined: API routes 500 in production but work in preview
Lovable white screen: blank preview or published app shows nothing
The Vibe Oops briefing
One email when something ships to production that should not have. New incidents, new error guides, no filler.