Home / Errors / Supabase / edge-function-non-2xx

'Edge Function returned a non-2xx status code' in Supabase and Lovable

Supabase Moderate 20-60 minutes Last verified Jul 17, 2026
The fix  Ignore the client message; it is a generic wrapper around any failure. Open Supabase dashboard > Edge Functions > your function > Logs (Lovable Cloud: Cloud > Functions/Logs) and read the real error. It is usually an uncaught exception (500), a missing secret, JWT verification rejecting the call (401), a CORS preflight failure, a wrong function name (404), or a timeout (546).

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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.

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

Related errors

The Vibe Oops briefing

One email when something ships to production that should not have. New incidents, new error guides, no filler.