错误处理:Prisma Client 错误码 P2000~P2034 速查
三类错误
Prisma Client 的错误分三大类,每类有不同的前缀和语义:
| 错误码范围 | 类别 | 含义 |
|---|
| P1xxx | 数据库连接错误 | Prisma 连不上数据库 |
| P2xxx | 已知请求错误 | Prisma Client 能识别的业务层错误(记录不存在、唯一冲突等) |
| P3xxx | Prisma 引擎内部错误 | 引擎崩溃、超时等底层问题 |
| P4xxx | Prisma Migrate 错误 | 迁移相关的错误(v7 起拆分) |
P2xxx 业务错误(最常见)
核心错误码速查
| 错误码 | 含义 | 典型场景 | HTTP 对应 |
|---|
| P2002 | 唯一约束冲突 | 创建 User 时 email 已存在 | 400 / 409 |
| P2025 | 记录不存在 | findUnique / update / delete 找不到记录 | 404 |
| P2003 | 外键约束失败 | Post.authorId 指向的 User 不存在 | 400 |
| P2014 | 关系违规——因外键不能删 | 尝试删 User 但他有关联的 Post | 409 |
| P2011 | 必填字段缺失 | 创建 Post 时没传 title 且它没有默认值 | 400 |
| P2012 | 必填关系字段缺失 | 创建 Post 时没传 author 关系 | 400 |
| P2028 | 事务查询数超限 | 交互事务里发送了太多查询 | 400 |
| P2034 | 事务失败(死锁/写冲突) | 并发事务互相等待 | 409(应该重试) |
处理示例
import { Prisma } from '@prisma/client'
try {
await prisma.user.create({
data: { email: 'alice@prisma.io', name: 'Alice' },
})
} catch (err) {
if (err instanceof Prisma.PrismaClientKnownRequestError) {
switch (err.code) {
case 'P2002':
// 从 err.meta.target 可以拿到冲突的字段名
const field = err.meta?.target as string[] | undefined
console.log(`唯一冲突:${field?.join(', ')}`)
break
case 'P2025':
console.log('记录不存在')
break
case 'P2003':
console.log('外键约束失败')
break
}
} else if (err instanceof Prisma.PrismaClientValidationError) {
// Schema 校验错误——查询参数和 Schema 对不上
console.log('参数格式错误')
}
}
P1xxx 连接错误(排查数据库)
| 错误码 | 含义 |
|---|
| P1001 | 连不上数据库服务器(DNS 解析失败、超时、防火墙) |
| P1002 | 数据库服务器响应超时(通常是连接池满了或服务器负载高) |
| P1003 | 数据库指定的目录不存在(SQLite 常见) |
| P1008 | 操作超时(比如迁移时 lock 等待超时) |
| P1017 | 数据库服务器已关闭连接 |
| P1020 | SSL 连接需要但没配(Serverless 平台常见) |
P1001 排查步骤
# 1. 用 prisma 自带的 doctor 检查
npx prisma doctor
# 2. 直接 ping 数据库
# PostgreSQL:
psql "postgresql://user:pass@host:5432/dbname"
# MySQL:
mysql -h host -u user -p dbname
Prisma 错误类型层级
Error
├── Prisma.PrismaClientKnownRequestError ← 有明确错误码的业务错误(P2xxx)
├── Prisma.PrismaClientValidationError ← 参数校验错误(Schema 不匹配)
├── Prisma.PrismaClientInitializationError ← 初始化失败(P1xxx 连接错误)
└── Prisma.PrismaClientRustPanicError ← 引擎崩溃(P3xxx,极其罕见)
类型守卫
用 instanceof 区分不同类型:
catch (err) {
if (err instanceof Prisma.PrismaClientKnownRequestError) {
// 有 code 属性,处理 P2xxx
} else if (err instanceof Prisma.PrismaClientValidationError) {
// 参数格式问题
} else {
// 其他未知错误
console.error(err)
}
}
生产环境错误处理策略
- 统一 PrismaError 过滤器(参考 NestJS 里的做法)
- P2002 映射为 400 Bad Request(告诉前端哪个字段重复)
- P2025 映射为 404 Not Found
- P2034 用循环重试(指数退避)
- P1xxx 记录详细日志并返回 503 Service Unavailable——数据库连不上是运维问题
- 永远不要 把原始 Prisma 错误对象的完整信息返回给客户端(可能含数据库结构)