# Edge Function returns 500

> Find and fix 500 errors from SupaHost Edge Functions. WORKER_ERROR means an uncaught exception; learn to read the Logs card, catch errors and return useful responses.

Source: https://supahost.app/kb/function-500 · Updated 2026-11-11

## What you see

The function returns `500 Internal Server Error`. If the runtime produced it, the response has this header:

```text
HTTP/2 500
sb-error-code: WORKER_ERROR
```

In the browser, supabase-js gives you a `FunctionsHttpError` and `data` is `null`. A 500 **without** `sb-error-code` was returned by your own code.

## Why it happens

`WORKER_ERROR` means your function threw an error that nothing caught, or a promise it awaited rejected. The runtime ended the request and returned a generic 500. Common triggers:

- A missing secret: `Deno.env.get('RESEND_API_KEY')` returned `undefined` and a library threw.
- Parsing a body that isn't JSON: `await req.json()` on an empty `GET` request.
- An external API call that failed or returned an unexpected shape.
- A database call where you used `data` without checking `error`.

## How to fix it

1. **Read the logs.** Go to *Dashboard → your project → **Functions** tab → Logs card*, pick the function in the filter, and look for the exception at the time of the request. The Logs card refreshes every 10 seconds. With an AI agent connected over MCP, `get_edge_function_logs` returns the same entries.
2. **Reproduce with the Test panel.** In the Functions tab, use **Test a function** to send the same method and body, as anon key or as service_role.
3. **Catch errors and return a real response.** Wrap the handler so failures are logged with context and the caller gets a clear message:

   ```ts
   Deno.serve(async (req) => {
     try {
       const { recipeId } = await req.json()
       if (!recipeId) {
         return Response.json({ error: 'recipeId is required' }, { status: 400 })
       }
       // ...work...
       return Response.json({ ok: true })
     } catch (err) {
       console.error('scale-recipe failed:', err)
       return Response.json({ error: 'Something went wrong' }, { status: 500 })
     }
   })
   ```

4. **Check secrets up front.** Fail early with a clear message instead of deep inside a library:

   ```ts
   const apiKey = Deno.env.get('RESEND_API_KEY')
   if (!apiKey) throw new Error('RESEND_API_KEY is not set')
   ```

   Add missing secrets in the Functions tab's Secrets card; changes reach functions within about a minute.
5. **Read the body on the client.** For a 500 your code returned, the JSON body has your message:

   ```js
   import { FunctionsHttpError } from '@supabase/supabase-js'

   const { error } = await supabase.functions.invoke('scale-recipe', { body: { recipeId: 7 } })
   if (error instanceof FunctionsHttpError) {
     console.error(await error.context.json())
   }
   ```

## On SupaHost

Function logs are kept by size, not by time: the newest entries are kept and older ones are trimmed, and the log endpoint returns at most 1,000 entries. Check soon after the error on busy projects. Each request also gets a log line with method, path, status and duration, which helps match a failure to a call. If the error says the function couldn't start rather than threw, see [Edge Function returns 503 or 504](/kb/function-503-504).

## Related

- [Logs and debugging](/docs/functions/logs)
- [Environment variables and secrets](/docs/functions/secrets)
- [Edge Function returns 503 or 504](/kb/function-503-504)
- [Inspecting function environment variables](/kb/function-env-vars)
