mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
docs: Supabase edge functions 404 troubleshooting (#43488)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Docs update ## What is the current behavior? No 404 debugging guide for edge functions ## What is the new behavior? Now there's a guide --------- Co-authored-by: Chris Chinchilla <chris.ward@supabase.io> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Chris Chinchilla <chris@chrischinchilla.com>
This commit is contained in:
9 files changed
+281
No files matched your search
@@ -0,0 +1,160 @@
|
||||
---
|
||||
title = "Edge Function 401 error response"
|
||||
topics = [ "functions" ]
|
||||
keywords = [ "401", "error" ]
|
||||
|
||||
[[errors]]
|
||||
http_status_code = 401
|
||||
message = "Invalid JWT"
|
||||
---
|
||||
|
||||
The function rejected the request for lacking the appropriate authorization headers.
|
||||
|
||||
## Context for the error
|
||||
|
||||
#### The JWT verification check
|
||||
|
||||
By default, edge functions are configured to check requests for a valid [legacy key](/docs/guides/api/api-keys#overview).
|
||||
|
||||
#### How the check causes 401 errors
|
||||
|
||||
The check will fail and return a 401 permission error if:
|
||||
|
||||
- The request includes an invalid legacy key, or
|
||||
- The request uses the newer asymmetric keys instead of a legacy key.
|
||||
|
||||
#### What this check actually does
|
||||
|
||||
This validation provides limited security value. It only confirms that the request includes a legacy token associated with your project, such as the anon key.
|
||||
|
||||
It does not validate the user's identity or permissions beyond that.
|
||||
|
||||
Because the security check is weak, it was deprecated when used with the new asymmetric keys.
|
||||
|
||||
## Solving the error
|
||||
|
||||
### Step 1: Identifying the error
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
If the tests return a 401 but don't match the criteria below, the error is coming from your app logic, not the JWT check.
|
||||
|
||||
</Admonition>
|
||||
|
||||
### Inspecting the return message
|
||||
|
||||
When an edge function fails due to a platform 401 error, it will return the error:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 401,
|
||||
"message": "Invalid JWT"
|
||||
}
|
||||
```
|
||||
|
||||
### Inspecting the logs
|
||||
|
||||
Your code may return a 401 error due to its own logic
|
||||
|
||||
```js
|
||||
return new Response(JSON.stringify(data), {
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
status: 401, // app logic returning a 401
|
||||
})
|
||||
```
|
||||
|
||||
A 401 status code alone doesn't confirm a JWT check failure by itself. The log must also lack an `execution_id`.
|
||||
|
||||

|
||||
|
||||
Instead of manually reviewing the logs, you can run the below query in the [log explorer](</dashboard/project/_/logs/explorer?q=SELECT+DISTINCT%0A++++req.pathname+AS+function_name,%0A++++res.status_code%0A++FROM+function_edge_logs%0A++CROSS+JOIN+UNNEST(metadata)+AS+metadata+%0A++CROSS+JOIN+UNNEST(metadata.request)+AS+req+%0A++CROSS+JOIN+UNNEST(metadata.response)+AS+res+%0AWHERE+status_code+=+401+AND+metadata.execution_id+IS+NULL%0ALIMIT+10;&its=&ite=>) to get a list of functions that were impacted by the check:
|
||||
|
||||
```sql
|
||||
select distinct
|
||||
req.pathname as function_name,
|
||||
res.status_code
|
||||
from
|
||||
function_edge_logs
|
||||
cross join UNNEST(metadata) as metadata
|
||||
cross join UNNEST(metadata.request) as req
|
||||
cross join UNNEST(metadata.response) as res
|
||||
where status_code = 401 and metadata.execution_id is null
|
||||
limit 10;
|
||||
```
|
||||
|
||||
### Step 2: Disabling the JWT check
|
||||
|
||||
The JWT check provides minimal security benefits, so we now recommend handling authentication through app logic instead. See the [Edge Function Auth Doc](/docs/guides/functions/auth) for details.
|
||||
|
||||
If you've migrated to [asymmetric keys (publishable/secret)](/dashboard/project/_/settings/api-keys) or no longer need the JWT check, you can disable it using one of the three options below:
|
||||
|
||||
<Accordion
|
||||
type="default"
|
||||
openBehaviour="multiple"
|
||||
chevronAlign="right"
|
||||
justified
|
||||
size="medium"
|
||||
className="text-foreground-light mt-8 mb-6"
|
||||
>
|
||||
<div className="border-b mt-3 pb-3">
|
||||
<AccordionItem
|
||||
header="In the Dashboard"
|
||||
id="item-1"
|
||||
>
|
||||
In the [Function Dashboard](/dashboard/project/_/functions/), under the offending function's detail tab, you can toggle off the check:
|
||||
|
||||

|
||||
|
||||
|
||||
</AccordionItem>
|
||||
|
||||
</div>
|
||||
<div className="border-b mt-3 pb-3">
|
||||
<AccordionItem
|
||||
header="With the Management API"
|
||||
id="item-2"
|
||||
>
|
||||
|
||||
1. Generate a secret token in the [Account Preferences Dashboard](/dashboard/account/tokens)
|
||||
2. Get your project ID from the [General Settings](/dashboard/project/_/settings/general)
|
||||
3. Substitute in the `PROJECT_ID`, `FUNCTION_NAME`, and `SECRET_TOKEN` in below [management endpoint](/docs/reference/api/v1-update-a-function). Then execute the request from a terminal environment
|
||||
|
||||
```sh
|
||||
# remember to substitute in your PROJECT_ID, FUNCTION_NAME, and SECRET_TOKEN
|
||||
|
||||
curl 'https://api.supabase.com/v1/projects/PROJECT_ID/functions/FUNCTION_NAME?verify_jwt=false' \
|
||||
--request PATCH \
|
||||
--header 'Content-Type: application/vnd.denoland.eszip' \
|
||||
--header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
|
||||
--data '""'
|
||||
|
||||
````
|
||||
</AccordionItem>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="border-b mt-3 pb-3">
|
||||
<AccordionItem
|
||||
header="With the Supabase CLI"
|
||||
id="item-3"
|
||||
>
|
||||
|
||||
With the [Supabase CLI](/docs/guides/local-development/cli/getting-started), you can redeploy your edge function without the JWT check:
|
||||
|
||||
```sh
|
||||
supabase functions deploy hello-world --no-verify-jwt
|
||||
````
|
||||
|
||||
</AccordionItem>
|
||||
|
||||
</div>
|
||||
</Accordion>
|
||||
|
||||
If you would like to continue using the JWT check, make sure that your [Supabase Client](/docs/guides/api/rest/client-libs) only uses your [legacy keys](/dashboard/project/_/settings/api-keys/legacy).
|
||||
|
||||
## Additional resources
|
||||
|
||||
- [Securing Edge Functions](/docs/guides/functions/auth)
|
||||
- [Debugging Edge Functions](/docs/guides/functions/logging)
|
||||
- [Quickstart Deployment: Dashboard](/docs/guides/functions/quickstart-dashboard)
|
||||
- [Quickstart Deployment: CLI](/docs/guides/functions/quickstart)
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title = "Edge Function 404 error response"
|
||||
topics = [ "functions" ]
|
||||
keywords = [ "404", "error" ]
|
||||
|
||||
[[errors]]
|
||||
http_status_code = 404
|
||||
code = "NOT_FOUND"
|
||||
message = "Requested function was not found"
|
||||
---
|
||||
|
||||
The edge function is not recognized by Supabase
|
||||
|
||||
## Context for the error
|
||||
|
||||
If the Supabase Edge Function Runtime does not recognize the function specified in the URL endpoint:
|
||||
|
||||
```sh
|
||||
https://PROJECT_REF.supabase.co/functions/v1/UNRECOGNIZED_FUNCTION_NAME
|
||||
```
|
||||
|
||||
then the runtime will return a 404 error.
|
||||
|
||||
## Solving the error
|
||||
|
||||
### Step 1: Identifying the error
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
If the tests return a 404 but don't match the criteria below, the error is coming from your app logic, not the JWT check.
|
||||
|
||||
</Admonition>
|
||||
|
||||
### Inspecting the return message from the request
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
Platform 404 errors cannot be detected in the browser. Instead, to confirm 404s from the browser, you must [check the logs](#inspecting-the-logs) instead.
|
||||
|
||||
Browsers misreport 404s as generic `CORS errors`. As a result, the [Supabase JavaScript client](/docs/reference/javascript/introduction) surfaces only a generic message: `Failed to send a request to the Edge Function`.
|
||||
|
||||
</Admonition>
|
||||
|
||||
When an edge function fails due to a platform 404 error, it will return the error:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "NOT_FOUND",
|
||||
"message": "Requested function was not found"
|
||||
}
|
||||
```
|
||||
|
||||
### Inspecting the logs
|
||||
|
||||
<Admonition type='tip'>
|
||||
|
||||
Always configure an appropriate time frame when using the log explorer
|
||||
|
||||

|
||||
|
||||
</Admonition>
|
||||
|
||||
One cannot inspect the function dashboard to find platform 404 errors, instead, you must run the below query in the [log explorer](/dashboard/project/_/logs/explorer?q=SELECT+DISTINCT%0A++++req.pathname+AS+function_name%2C%0A++++res.status_code%0AFROM+function_edge_logs%0ACROSS+JOIN+UNNEST%28metadata%29+AS+metadata+%0ACROSS+JOIN+UNNEST%28metadata.request%29+AS+req+%0ACROSS+JOIN+UNNEST%28metadata.response%29+AS+res+%0AWHERE+%0A++++status_code+%3D+404+%0A++++++++AND+%0A++++metadata.execution_id+IS+NULL%0ALIMIT+10%3B). Results will show all requests that reached Supabase but were rejected as unrecognizable.
|
||||
|
||||
```sql
|
||||
select distinct
|
||||
req.pathname as function_name,
|
||||
res.status_code
|
||||
from
|
||||
function_edge_logs
|
||||
cross join UNNEST(metadata) as metadata
|
||||
cross join UNNEST(metadata.request) as req
|
||||
cross join UNNEST(metadata.response) as res
|
||||
where status_code = 404 and metadata.execution_id is null
|
||||
limit 10;
|
||||
```
|
||||
|
||||
### Step 2: Check the function for typos
|
||||
|
||||
In your code, make sure your function name doesn't have any typos, such as:
|
||||
|
||||
- miscapitalization
|
||||
- em-dashes instead of dashes
|
||||
- misplaced characters
|
||||
- unnecessary slashes `///`
|
||||
|
||||
### Step 3: Try calling the function from the dashboard
|
||||
|
||||
When selecting your function in the [Function Dashboard](/dashboard/project/_/functions), you should have the option to make a test call:
|
||||
|
||||

|
||||
|
||||
If the call works, consider double checking your code for typos or to see if it is overwriting the function name dynamically. Otherwise, go on to step 4.
|
||||
|
||||
### Step 4: Redeploy the function
|
||||
|
||||
If step 3 fails, it may be a sign of an internal bug and it may be necessary to redeploy your function. This can be done within the [Function Dashboard](/dashboard/project/_/functions) under the respective function's code tab:
|
||||
|
||||

|
||||
|
||||
Alternatively, if you develop locally, you can redeploy the function with the [Supabase CLI](/docs/guides/local-development/cli/getting-started?queryGroups=platform&platform=macos):
|
||||
|
||||
```sh
|
||||
supabase functions deploy FUNCTION_NAME
|
||||
|
||||
# If you want to deploy all functions, run the `deploy` command without specifying a function name:
|
||||
supabase functions deploy
|
||||
```
|
||||
|
||||
Then write in a ticket to [Supabase Support](/dashboard/support/new)
|
||||
|
||||
## Additional resources
|
||||
|
||||
- [Securing Edge Functions](/docs/guides/functions/auth)
|
||||
- [Debugging Edge Functions](/docs/guides/functions/logging)
|
||||
- [Quickstart Deployment: Dashboard](/docs/guides/functions/quickstart-dashboard)
|
||||
- [Quickstart Deployment: CLI](/docs/guides/functions/quickstart)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 225 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 210 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 143 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 113 KiB |
@@ -59,6 +59,8 @@ allow_list = [
|
||||
"[Dd]ropdown",
|
||||
"DuckDB",
|
||||
"EarlyDrop",
|
||||
"[Ee]m-dash",
|
||||
"[Ee]m-dashes",
|
||||
"[Ee]nqueues?",
|
||||
"[Ee]ntrypoints?",
|
||||
"[Ee]nums?",
|
||||
@@ -91,6 +93,8 @@ allow_list = [
|
||||
"[Mm]icroservices?",
|
||||
"microtasks",
|
||||
"[Mm]iddlewares?",
|
||||
"[Mm]iscapitalization",
|
||||
"[Mm]isreport",
|
||||
"[Mm]onorepos?",
|
||||
"[Mm]ultimodal",
|
||||
"[Mm]ultipart",
|
||||
|
||||
Reference in new issue
Block a user