You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Prisma.user.update()报错:nome参数不可为null的解决求助

解决Prisma更新用户名称时nome参数不可为null的问题

问题描述

使用Prisma更新数据库中的用户名称(nome)时,系统提示nome参数不可为null,但表单中已填写该字段,需排查解决此问题。

报错信息

Error: 
Invalid `prisma.user.update()` invocation:

{
  where: {
    id: "kp_fa1706a59b5348b384c9e62cb0bf59df"
  },
  data: {
+   nome: String
  }
}

Argument `nome` must not be null.

原始代码

Server Action函数

"use server";

import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";
import { redirect } from "next/navigation";
import { prisma } from "./lib/db";
import { Prisma } from "@prisma/client";

export async function updateName() {
  const { getUser } = getKindeServerSession();
  const user = await getUser();
  const formData = new FormData();

  if (!user) {
    return redirect("/api/auth/login");
  }

  const nome = formData.get("nome");

  try {
    await prisma.user.update({
      where: {
        id: user.id,
      },
      data: {
        nome: nome,
      },
    });

    return {
      message: "Succesfully Updated name",
      status: "green",
    };
  } catch (e) {
    if (e instanceof Prisma.PrismaClientKnownRequestError) {
      if (e.code === "P2002") {
        return {
          message: "This username is alredy used",
          status: "error",
        };
      }
    }

    throw e;
  }
}

Prisma Schema定义

model User {
  id                        String @id
  nome                      String
  cognome                   String
  email                     String
  imageUrl                  String?
  Paziente Paziente[]
}

补充代码(表单与提交按钮)

// 表单组件
"use client";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import Link from "next/link";
import { updateName } from "@/app/actions";
import { SubmitButton } from "../utility/SubmitButtons";
import { useFormState } from "react-dom";
import { useEffect } from "react";
import { useToast } from "@/components/ui/use-toast";

const initialState = {
  message: "",
  status: "",
};

export function SettingsForm({ nome }) {
  const [state, formAction] = useFormState(updateName, initialState);
  const { toast } = useToast();

  useEffect(() => {
    if (state?.status === "green") {
      toast({
        title: "Succesfull",
        description: state.message,
      });
    } else if (state?.status === "error") {
      toast({
        title: "Error",
        description: state.message,
        variant: "destructive",
      });
    }
  }, [state, toast]);
  return (
    <form action={formAction}>
      <h1 className="text-3xl font-extrabold tracking-tight">Settings</h1>

      <Separator className="my-4" />
      <Label className="text-lg">Name</Label>
      <p className="text-muted-foreground">
        In this Settings page you can change your name!
      </p>

      <Input
        defaultValue={nome}
        name="nome"
        required
        className="mt-2"
        min={2}
        maxLength={21}
      />

      {state?.status === "error" && (
        <p className="text-destructive mt-1">{state.message}</p>
      )}

      <div className="w-full flex mt-5 gap-x-5 justify-end">
        <Button variant="secondary" asChild type="button">
          <Link href="/">Cancel</Link>
        </Button>
        <SubmitButton text="Change Username" />
      </div>
    </form>
  );
}

// 提交按钮组件
"use client";

import { Button } from "@/components/ui/button";
import { ArrowDown, ArrowUp, Loader2 } from "lucide-react";
import { useFormStatus } from "react-dom";

export function SubmitButton({ text }) {
  const { pending } = useFormStatus();
  return (
    <>
      {pending ? (
        <Button disabled>
          <Loader2 className="mr-2 w-4 h-4 animate-spin" />
          Please wait
        </Button>
      ) : (
        <Button type="submit">{text}</Button>
      )}
    </>
  );
}

export function SaveButton() {
  const { pending } = useFormStatus();
  return (
    <>
      {pending ? (
        <Button className="mt-2 w-full" disabled size="sm">
          <Loader2 className="mr-2 h-3 w-3 animate-spin" />
          Please wait
        </Button>
      ) : (
        <Button size="sm" className="mt-2 w-full" type="submit">
          Save
        </Button>
      )}
    </>
  );
}

export function UpVote() {
  const { pending } = useFormStatus();

  return (
    <>
      {pending ? (
        <Button variant="outline" size="icon" disabled>
          <Loader2 className="h-4 w-4 animate-spin" />
        </Button>
      ) : (
        <Button variant="outline" size="sm" type="submit">
          <ArrowUp className="h-4 w-4" />
        </Button>
      )}
    </>
  );
}
export function DownVote() {
  const { pending } = useFormStatus();

  return (
    <>
      {pending ? (
        <Button variant="outline" size="icon" disabled>
          <Loader2 className="h-4 w-4 animate-spin" />
        </Button>
      ) : (
        <Button variant="outline" size="sm" type="submit">
          <ArrowDown className="h-4 w-4" />
        </Button>
      )}
    </>
  );
}

问题根源

Server Action函数中手动创建了空的FormData对象,导致formData.get("nome")返回null。Next.js的Server Action在表单提交时,会自动将用户填写的表单数据以FormData的形式作为参数传递给action函数,无需手动实例化FormData。

解决方案

修改Server Action函数,接收自动传递的FormData参数,并添加必要的参数校验:

修改后的Server Action

"use server";

import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";
import { redirect } from "next/navigation";
import { prisma } from "./lib/db";

export async function updateName(formData) {
  const { getUser } = getKindeServerSession();
  const user = await getUser();

  if (!user) {
    return redirect("/api/auth/login");
  }

  // 从表单数据中获取nome字段
  const nome = formData.get("nome");
  
  // 添加参数校验:确保nome是有效字符串且不为空
  if (!nome || typeof nome !== "string" || nome.trim().length === 0) {
    return {
      message: "名称不能为空",
      status: "error",
    };
  }

  try {
    await prisma.user.update({
      where: {
        id: user.id,
      },
      data: {
        nome: nome.trim(), // 去除首尾空格后存入数据库
      },
    });

    return {
      message: "名称更新成功",
      status: "green",
    };
  } catch (e) {
    // 处理Prisma已知错误
    if (e instanceof prisma.Prisma.PrismaClientKnownRequestError) {
      if (e.code === "P2002") {
        return {
          message: "该用户名已被使用",
          status: "error",
        };
      }
    }

    // 处理其他未知错误
    return {
      message: "更新失败,请稍后重试",
      status: "error",
    };
  }
}

额外优化建议

  1. 前端表单中,Input组件的min属性改为minLength(min针对数字输入,字符串输入需用minLength):
<Input
  defaultValue={nome}
  name="nome"
  required
  className="mt-2"
  minLength={2}
  maxLength={21}
/>
  1. 可在前端添加实时校验,提前拦截无效输入,提升用户体验。

内容的提问来源于stack exchange,提问作者Federico Fan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 13:29:51