Logs and debugging
Read Edge Function logs on SupaHost in the Functions tab, over MCP or SSH, understand router error codes like BOOT_ERROR and IDLE_TIMEOUT, and debug failing functions.
Each project with functions keeps one log of everything its functions print and every request they answer. You can read it in the dashboard, from an AI agent over MCP, or over SSH on Business plans. There's no searchable log explorer, and the project Logs tab is still marked coming soon, so this function log is where to look.
Where to read logs
The Logs card
Dashboard → your project → Functions tab → Logs card. It shows the newest 200 entries with Time, Function (with the version that ran), Level and Message. Pick a function from the All functions menu to filter, or click Refresh. The card also refreshes itself every 10 seconds, so you can leave it open while you test.
Every member of the team can read the Logs card.
From an AI agent
The MCP tool get_edge_function_logs returns recent entries, newest first. It takes an optional function_slug and a limit of up to 500 (default 100). A prompt like "Read the last 50 log lines for invoice-reminders and tell me why it returns 500" works well. See MCP tools reference.
Over SSH (Business and Enterprise)
With SSH access set up, print the last 200 lines, or follow new ones:
ssh [email protected]
# then, on the instance:
sudo supahost-logs app-one functions # last 200 lines
sudo supahost-logs app-one functions --follow # keep streaming
What gets logged
| Type | Level | What it contains |
|---|---|---|
log |
info, warn or error | Your console.log / console.info, console.warn, console.error output |
request |
info, or error for 5xx | One line per request: method, path, status and duration, e.g. POST /invoice-reminders → 200 in 182 ms |
boot |
info or error | "Booted in N ms", or the reason a worker failed to start |
exception |
error | Uncaught exceptions with the stack trace |
shutdown |
info | A worker stopping, with CPU time and memory used |
Log structured values to make them easier to read later:
console.log(JSON.stringify({ event: "reminder_sent", invoiceId: invoice.id, ms: Date.now() - t0 }));
console.error("Resend rejected the email", res.status, await res.text());
Don't log secrets, access tokens or whole request headers.
How long logs are kept
Retention is by size, not time. The log file is capped at 8 MB; when it passes that, it's trimmed to the most recent 2 MB. Readers look at the last 3 MB and return at most 1000 entries. A quiet project keeps days of history; a busy one may keep only minutes.
If you need a lasting record (payments, audit events), write it to a table from the function instead of relying on the log.
Error codes from the router
When something fails outside your code, the router answers with a JSON body and an sb-error-code header:
| Status | sb-error-code |
What it means | Where to look |
|---|---|---|---|
| 404 | NOT_FOUND |
No live function with that name. | Check the name and that the status is Live. Returns 404 |
| 401 | UNAUTHORIZED_NO_AUTH_HEADER |
Require a JWT is on and no Authorization header was sent. |
Returns 401 |
| 401 | UNAUTHORIZED_INVALID_JWT |
The token isn't a valid, unexpired JWT from this project. | Returns 401 |
| 503 | BOOT_ERROR |
The worker couldn't start, often an error thrown at the top level of the module or a missing secret read at boot. | boot lines in the logs. 503 or 504 |
| 546 | WORKER_RESOURCE_LIMIT |
The worker ran out of resources (for example the 150 MB memory limit). The router retries such requests up to 2 times first. | shutdown lines show memory used. Memory limit |
| 504 | IDLE_TIMEOUT |
The function didn't start responding within 150 seconds. | Timeouts |
| 500 | WORKER_ERROR |
The function threw an error that wasn't caught. | exception lines. Returns 500 |
Responses your own code returns never have sb-error-code, so that header tells you which side produced the error.
A debugging routine
- Reproduce it in the dashboard. The Test a function card (owner only) sends a real request as the anon key or as
service_roleand shows status, duration, anysb-error-codeand up to 64 KB of the body. - Read the logs for that request. Filter the Logs card to the function. Look for
exceptionorbooterrors just before therequestline. - Add logging around the suspect code, deploy a new version, and repeat. Each deploy takes about a minute, and the old version keeps serving until the new one is live.
- Check the deploy status. If the row says Deploy failed, your latest code isn't running at all; the build error is under the function's URL.
- Check the caller. A
401with ansb-error-codemeans the request never reached your code. Compare the token you're sending with Authentication and JWT verification. - Run it locally with
supabase functions serveif you need a debugger or faster iteration (see Local development with the Supabase CLI).