mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
docs: add guide on reading error.hint in supabase-js (#46556)
New guide at `/guides/api/handling-errors-in-supabase-js` that leads
with `error.hint` as the most useful field on a Postgres error. When the
database knows the fix (a `GRANT` statement to run for a `42501`, a
column name you probably meant), it puts the literal SQL in `hint`.
Logging only `error.message` hides it.
The guide covers the `PostgrestError` shape (fields ordered by
usefulness: hint first, message last), branching on `error.code`, and
parallel patterns for Auth, Storage, Edge Functions, and Realtime.
Linked from the API > Guides sidebar next to the existing PostgREST
error codes reference.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Added a comprehensive guide on handling errors in supabase-js,
explaining the {data, error} pattern and recommending logging full error
objects.
* Provides a recommended error-handling pattern, guidance to branch on
error codes, and example error fields.
* Adds component-specific advice for Auth, Storage, Edge Functions, and
Realtime, plus a “Related” links section.
* Added a navigation entry so the guide appears in the API guides
submenu.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
1 parent
19e6e17257
commit
87f880e669
2 files changed
+149
No files matched your search
@@ -1571,6 +1571,10 @@ export const api: NavMenuConstant = {
|
||||
{ name: 'Generating TypeScript Types', url: '/guides/api/rest/generating-types' },
|
||||
{ name: 'Generating Python Types', url: '/guides/api/rest/generating-python-types' },
|
||||
{ name: 'Error Codes', url: '/guides/api/rest/postgrest-error-codes' },
|
||||
{
|
||||
name: 'Handling Errors in supabase-js',
|
||||
url: '/guides/api/handling-errors-in-supabase-js',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
id: handling-errors-in-supabase-js
|
||||
title: 'Handling errors in `supabase-js`'
|
||||
subtitle: 'Read `error.hint` first — Postgres often tells you the exact fix. Log the full error so you actually see it.'
|
||||
---
|
||||
|
||||
Every `supabase-js` call returns a `{ data, error }` pair instead of throwing. When something fails, the single most useful field on `error` is usually `hint` — Postgres returns the _fix_, not just a description of the problem. Logging only `error.message` hides it.
|
||||
|
||||
## Usage of `message` and `hint` properties
|
||||
|
||||
Consider a `42501` permission-denied error on a table where default `GRANT`s have been revoked from `anon`:
|
||||
|
||||
```
|
||||
message: "permission denied for table users"
|
||||
hint: "Grant the required privileges to the current role with: GRANT SELECT ON public.users TO anon;"
|
||||
```
|
||||
|
||||
The `message` exposes the error reason, and `hint` gives you the literal SQL statement to run in the dashboard SQL editor to fix it.
|
||||
|
||||
The same pattern shows up across many Postgres errors — missing column? `hint` suggests the column name you probably meant. Type mismatch? `hint` shows the expected type. Whenever Postgres knows the fix, it puts it in `hint`.
|
||||
|
||||
<Admonition type="tip">Log the full `error` object, not just `error.message`.</Admonition>
|
||||
|
||||
## The recommended pattern
|
||||
|
||||
Read `{ data, error }` from the response, check `error`, log the whole object, and return early.
|
||||
|
||||
```ts
|
||||
const { data, error } = await supabase.from('users').select()
|
||||
if (error) {
|
||||
console.error(error)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
In the case of a permission-denied error, the response body will look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "42501",
|
||||
"message": "permission denied for table users",
|
||||
"details": null,
|
||||
"hint": "Grant the required privileges to the current role with: GRANT SELECT ON public.users TO anon;"
|
||||
},
|
||||
"status": 401,
|
||||
"statusText": "Unauthorized"
|
||||
}
|
||||
```
|
||||
|
||||
`postgrest-js` passes the body through verbatim, so `error.hint` is the exact string Postgres produced. Treat it as the answer the database is giving you, not as a suggestion to file away.
|
||||
|
||||
## The `PostgrestError` fields, by usefulness
|
||||
|
||||
Database calls (`select`, `insert`, `update`, `upsert`, `delete`, `rpc`) return a `PostgrestError` with four fields. Read them in roughly this order:
|
||||
|
||||
| Field | Read it when |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| `hint` | Always check first. When Postgres includes one, it's the actionable fix (a `GRANT` to run, a column name, a type). |
|
||||
| `code` | When branching in code. Codes are stable across versions; `message` text isn't. |
|
||||
| `details` | When `hint` and `message` aren't enough. Often contains the offending value, key, or row. |
|
||||
| `message` | As the human summary. Useful in UI strings, less useful for debugging. |
|
||||
|
||||
A full list of PostgREST error codes is in the [Error Codes reference](/guides/api/rest/postgrest-error-codes).
|
||||
|
||||
## Branch on `error.code`, not `error.message`
|
||||
|
||||
`error.code` is more reliable than `error.message` for programmatic branching: messages change between Postgres and PostgREST versions, but codes are stable.
|
||||
|
||||
```ts
|
||||
const { data, error } = await supabase.from('users').select()
|
||||
if (error) {
|
||||
console.error(error)
|
||||
if (error.code === '42501') {
|
||||
// Permission denied. error.hint usually contains the GRANT to run.
|
||||
}
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
## Errors from Auth, Storage, and Edge Functions
|
||||
|
||||
The same rule applies across the SDK — log the whole error object — but the shape differs by client.
|
||||
|
||||
### Auth
|
||||
|
||||
`AuthError` exposes `error.code` (e.g. `'invalid_credentials'`, `'email_not_confirmed'`) and `error.status`. Branch on `code`; log the whole thing.
|
||||
|
||||
```ts
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email: 'example@email.com',
|
||||
password: 'example-password',
|
||||
})
|
||||
if (error) {
|
||||
console.error(error)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
### Storage
|
||||
|
||||
`StorageError` exposes `error.statusCode` (HTTP status as a string) and a structured `error` name (e.g. `'Duplicate'`, `'NotFound'`).
|
||||
|
||||
```ts
|
||||
const { data, error } = await supabase.storage
|
||||
.from('avatars')
|
||||
.upload('public/avatar1.png', avatarFile)
|
||||
if (error) {
|
||||
console.error(error)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
### Edge Functions
|
||||
|
||||
Functions errors arrive as one of three subclasses. Narrow with `instanceof`; for `FunctionsHttpError`, parse the body to get the function's own error payload.
|
||||
|
||||
```ts
|
||||
import { FunctionsFetchError, FunctionsHttpError, FunctionsRelayError } from '@supabase/supabase-js'
|
||||
|
||||
const { data, error } = await supabase.functions.invoke('hello')
|
||||
if (error instanceof FunctionsHttpError) {
|
||||
console.error('Function error', await error.context.json())
|
||||
} else if (error) {
|
||||
console.error(error)
|
||||
}
|
||||
```
|
||||
|
||||
### Realtime
|
||||
|
||||
The `subscribe()` callback receives a `status` and, on failure, an `err` argument. Log the whole `err` — its `cause` often holds the underlying reason.
|
||||
|
||||
```ts
|
||||
supabase.channel('room1').subscribe((status, err) => {
|
||||
if (status === 'CHANNEL_ERROR' || status === 'TIMED_OUT') {
|
||||
console.error(status, err)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [PostgREST Error Codes](/guides/api/rest/postgrest-error-codes)
|
||||
- [Automatic retries with `supabase-js`](/guides/api/automatic-retries-in-supabase-js)
|
||||
- [Securing your API](/guides/api/securing-your-api)
|
||||
Reference in new issue
Block a user