Next.js T3栈应用中tRPC Mutation的500内部服务器错误排查
T3栈应用调用auth.UserChecker mutation时返回500内部服务器错误
技术栈
- Next.js
- NextAuth.js
- Prisma
- Tailwind CSS
- tRPC
错误场景
调用auth.UserChecker mutation进行登录凭证验证时,服务器返回500内部服务器错误。注册页与登录页结构一致,仅输入项不同。错误触发位置为src/server/api/routers/auth.ts中的UserChecker路由,被src/components/auth/login.tsx和register.tsx调用,应用其余配置为默认。
相关代码
login.tsx
"use client"; import { api } from "@/trpc/react"; function Login() { const { toast } = useToast(); const UserChecker = api.auth.UserChecker.useMutation({ onSuccess: (response) => { console.log("Mutation successful", response); // Handle successful mutation, e.g., redirect or update UI }, onError: (error) => { console.log("Mutation error", error); toast({ variant: "destructive", title: "Error", description: "An error occurred during login." }); } }) const [user, setNewUser] = useState({ email: "", password: "", }); const loginForm = z.object({ email: z .string() .min(1, { message: "This field has to be filled." }) .email("This is not a valid email."), password: z.string().min(1, { message: "This field has to be filled" }), }); async function LoginFormSubmet() { const validUser = loginForm.safeParse(user); if (validUser.data) { console.log("4"); const Data = validUser.data; UserChecker.mutate(Data) } } return ( <> Input will be here. <Button className=" relative w-48" onClick={(e) => { e.preventDefault(); LoginFormSubmet(); }} > {" "} Register </Button> </> ); } export default Login;
auth.ts(tRPC路由)
import { object, z } from "zod"; import bcrypt from 'bcryptjs'; import { createTRPCRouter, protectedProcedure, publicProcedure, } from "@/server/api/trpc"; export const authRouter = createTRPCRouter({ UserChecker:publicProcedure.input(z.object({email:z.string() ,password:z.string()})) .mutation(async({ctx,input})=>{ console.log(input); return JSON.parse(JSON.stringify({data:"password"})); }), makeNewUser:publicProcedure.input(z.object({ name: z.string().min(1 ,{message:"This field has to be filled."}), dateOfBirth:z.string().min(1 ,{message:"This field has to be filled."}), email:z.string().min(1, { message: "This field has to be filled." }).email("This is not a valid email."), password:z.string().min(5 ,{message:"password must be at least 5 characters"}), confirmPassword:z.string() })).mutation( async({ctx ,input})=>{ const FindUser = await ctx.db.user.findUnique({ where:{ email:input.email } }) if(FindUser){return{error:"this user exists"}} if(!FindUser){ const salt = await bcrypt.genSalt(10); const passwordHash = await bcrypt.hash(input.password, salt); const newUser = await ctx.db.user.create({ data:{ name:input.name, email:input.email, dateOfBirth:input.dateOfBirth, password:passwordHash } }) } }), findUser:publicProcedure.input(z.object({ email:z.string().min(1, { message: "This field has to be filled." }).email("This is not a valid email.") })).query(async({ ctx ,input}) =>{ return ctx.db.user.findUnique({where:{email:input.email}}) }), findUserValidation:publicProcedure.input(z.object({ email:z.string().min(1, { message: "This field has to be filled." }).email("This is not a valid email."), password:z.string(), })).mutation(async({ ctx ,input}) =>{ const FoundUser = await ctx.db.user.findUnique({where:{email:input.email}}) if(!FoundUser){return {error:"user Does not exist"}} const CheckPassword = await bcrypt.compare(input.password ,FoundUser.password) if(!CheckPassword){return{error:"user Does not exist"}} return{input} }) });
问题排查与解决方案
- 修复前端导入缺失
login.tsx中使用了useState和useToast但未导入,会导致前端运行时错误,影响请求发送。添加缺失的导入:
import { useState } from "react"; import { useToast } from "@/components/ui/toast"; // 路径根据实际项目调整
- 简化
UserChecker返回逻辑
原代码中JSON.parse(JSON.stringify({data:"password"}))属于多余操作,可能引发序列化异常,直接返回对象即可:
UserChecker: publicProcedure.input(z.object({email: z.string(), password: z.string()})) .mutation(async({ctx, input}) => { console.log(input); return { data: "password" }; }),
- 检查tRPC上下文配置
确保src/server/api/trpc.ts中正确注入Prisma客户端到上下文,比如:
import { prisma } from "@/server/db"; import { type CreateNextContextOptions } from "@trpc/server/adapters/next"; export const createTRPCContext = async (opts: CreateNextContextOptions) => { // 其他上下文逻辑 return { db: prisma, // ...其他上下文内容 }; };
如果上下文未正确注入db,调用ctx.db会直接抛出错误导致500。
查看服务器端日志
启动应用后观察终端输出,确认UserChecker中的console.log(input)是否打印。若未打印,说明路由未正确匹配;若打印后仍报错,查看具体错误信息(如Prisma连接失败、数据库字段缺失等)。验证Prisma配置
检查prisma/schema.prisma中的User模型是否包含email、password等必要字段,且已执行prisma migrate dev同步数据库结构。
内容的提问来源于stack exchange,提问作者OGZY MMO
相关产品推荐
相关产品推荐

