Skip to content
REST API

supabase-js 中处理错误

Read error.hint first — Postgres often tells you the exact fix. Log the full error so you actually see it.

每个 supabase-js 调用都会返回一个 { data, error } 对,而不是抛出异常。当某些操作失败时,error 上最有用的字段通常是 hint——Postgres 返回的是 修复方法,而不仅仅是问题描述。只记录 error.message 会把它隐藏起来。

🌐 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 only a description of the problem. Logging only error.message hides it.

messagehint#

🌐 Usage of message and hint properties

考虑一下在一个表上发生的 42501 权限被拒绝错误,其中默认的 GRANT 已从 anon 撤销:

🌐 Consider a 42501 permission-denied error on a table where default GRANTs have been revoked from anon:

1
message: "permission denied for table users"
2
hint: "Grant the required privileges to the current role with: GRANT SELECT ON public.users TO anon;"

message 会显示错误原因,hint 会给你要在仪表板 SQL 编辑器中运行的具体 SQL 语句来修复它。

🌐 The message exposes the error reason, and hint gives you the literal SQL statement to run in the dashboard SQL editor to fix it.

同样的模式出现在许多 Postgres 错误中——缺少列?hint 会提示你可能想要的列名。类型不匹配?hint 会显示预期的类型。每当 Postgres 知道如何修复时,它会把方法放在 hint 中。

🌐 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.

🌐 The recommended pattern

从响应中读取 { data, error },检查 error,记录整个对象,然后提前返回。

🌐 Read { data, error } from the response, check error, log the whole object, and return early.

1
const { data, error } = await supabase.from('users').select()
2
if (error) {
3
console.error(error)
4
return
5
}

如果遇到权限被拒绝的错误,响应内容会是这样的:

🌐 In the case of a permission-denied error, the response body will look like this:

1
{
2
"error": {
3
"code": "42501",
4
"message": "permission denied for table users",
5
"details": null,
6
"hint": "Grant the required privileges to the current role with: GRANT SELECT ON public.users TO anon;"
7
},
8
"status": 401,
9
"statusText": "Unauthorized"
10
}

postgrest-js 会逐字传递正文,所以 error.hint 是 Postgres 生成的精确字符串。把它当作数据库给你的答案,而不是存起来的建议。

PostgrestError#

🌐 The PostgrestError fields, by usefulness

数据库调用(selectinsertupdateupsertdeleterpc)会返回一个包含四个字段的 PostgrestError。大致按以下顺序读取它们:

🌐 Database calls (select, insert, update, upsert, delete, rpc) return a PostgrestError with four fields. Read them in roughly this order:

字段什么时候看
hint总是先检查。当 Postgres 包含时,它就是可操作的修复(一个需要运行的 GRANT,列名,类型)。
code在代码中分支时。代码在各版本间是稳定的;message 文本不是。
detailshintmessage 不够用时。通常包含有问题的值、键或行。
message作为人工摘要。有用在 UI 字符串中,但调试用途不大。

PostgREST 的完整错误代码列表可以在 错误代码参考 中找到。

🌐 A full list of PostgREST error codes is in the Error Codes reference.

error.code 上分支,而不是 error.message#

🌐 Branch on error.code, not error.message

error.codeerror.message 在程序分支上更可靠:消息在 Postgres 和 PostgREST 版本之间会变化,但代码是稳定的。

1
const { data, error } = await supabase.from('users').select()
2
if (error) {
3
console.error(error)
4
if (error.code === '42501') {
5
// Permission denied. error.hint usually contains the GRANT to run.
6
}
7
return
8
}

来自认证、存储和边缘函数的错误 #

🌐 Errors from Auth, Storage, and Edge Functions

同样的规则适用于整个 SDK —— 记录整个错误对象 —— 但不同客户端的结构不同。

🌐 The same rule applies across the SDK — log the whole error object — but the shape differs by client.

认证 #

🌐 Auth

AuthError 暴露了 error.code(例如 'invalid_credentials''email_not_confirmed')和 error.status。根据 code 分支;记录整个过程。

1
const { data, error } = await supabase.auth.signInWithPassword({
2
email: 'example@email.com',
3
password: 'example-password',
4
})
5
if (error) {
6
console.error(error)
7
return
8
}

存储 #

🌐 Storage

StorageError 显示了 error.statusCode(以字符串形式的 HTTP 状态)和结构化的 error 名称(例如 'Duplicate''NotFound')。

1
const { data, error } = await supabase.storage
2
.from('avatars')
3
.upload('public/avatar1.png', avatarFile)
4
if (error) {
5
console.error(error)
6
return
7
}

边缘函数 #

🌐 Edge Functions

函数错误分为三种子类之一。使用 instanceof 时是窄类;对于 FunctionsHttpError,解析函数体以获取函数自身的错误负载。

🌐 Functions errors arrive as one of three subclasses. Narrow with instanceof; for FunctionsHttpError, parse the body to get the function's own error payload.

1
import { FunctionsFetchError, FunctionsHttpError, FunctionsRelayError } from '@supabase/supabase-js'
2
3
const { data, error } = await supabase.functions.invoke('hello')
4
if (error instanceof FunctionsHttpError) {
5
console.error('Function error', await error.context.json())
6
} else if (error) {
7
console.error(error)
8
}

实时 #

🌐 Realtime

subscribe() 回调接收一个 status,在失败时还会接收一个 err 参数。把整个 err 打印出来 —— 它的 cause 通常包含了根本原因。

🌐 The subscribe() callback receives a status and, on failure, an err argument. Log the whole err — its cause often holds the underlying reason.

1
supabase.channel('room1').subscribe((status, err) => {
2
if (status === 'CHANNEL_ERROR' || status === 'TIMED_OUT') {
3
console.error(status, err)
4
}
5
})

🌐 Related