在Next.js路由处理器中打印Prisma错误对象时出现异常
代码示例
export async function PUT( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { const { id } = await params; const body = await request.json(); const updatedIssue = await prisma.issue.update({ where: { id: parseInt(id) }, data: { title: body.title, description: body.description, }, }); return NextResponse.json(updatedIssue); } catch (error) { console.error(error); return NextResponse.json(error, { status: 500 }); } }
现象描述
当捕获到Prisma客户端错误(如更新不存在的记录)时,调用console.error(error)会抛出新错误:
TypeError: The "payload" argument must be of type object. Received null
此时接口返回500状态码但无响应体。若移除console.error(error)语句,接口会返回正常的错误响应体:
{ "name": "PrismaClientKnownRequestError", "code": "P2025", "clientVersion": "6.1.0", "meta": { "modelName": "Issue", "cause": "Record to update not found." } }
若改为console.error(JSON.stringify(error)),则能正常打印错误信息,且接口返回正确的响应体。想请教该现象的原因,是否与Next.js底层封装console有关?
原因分析
这个问题确实和Next.js对console的封装有关,核心是Prisma错误对象的特殊性与Next.js日志处理逻辑的冲突:
Prisma错误对象的特殊结构
Prisma抛出的PrismaClientKnownRequestError等错误并非普通JS Error实例,它包含大量非枚举属性或内部循环引用。直接传递给console.error时,Next.js的日志序列化逻辑无法正确处理这些特殊结构,最终返回null,触发TypeError。Next.js对服务器端console的封装
Next.js在服务器端(App Router路由处理器属于服务器端代码)对console做了封装,用于统一日志格式、对接日志系统。但这个封装逻辑在处理复杂错误对象时,没有做足够的兼容处理——当遇到无法序列化的属性或循环引用时,会直接返回null,导致后续报错。JSON.stringify的兼容作用
使用JSON.stringify(error)时,会自动过滤循环引用和非枚举属性,只保留可序列化的核心字段(如name、code、meta)。此时console.error接收的是合法字符串,不会触发序列化异常;同时NextResponse.json(error)能正常处理错误对象的序列化,返回正确响应体。
额外说明:NextResponse.json内部对Error对象做了专门的序列化兼容,但Next.js封装的console.error没有实现同样的逻辑,这才导致了代码中出现的矛盾现象。
内容的提问来源于stack exchange,提问作者4rrow

