0

I'm building a guest creation API using Next.js (App Router), Zod, and Mongoose.

The problem:
Even though my frontend validation passes and I see the full payload in the console, the server throws validation errors and still creates the document. On the next request it then says the email already exists.

I am also using TanStack, and this API has a retry count of 2, which is why there are two response at the same time.

First error response:

{
  "message": "Server error",
  "error": "Guest validation failed: createdBy: Path `createdBy` is required., email: Path `email` is required., lastName: Path `lastName` is required., firstName: Path `firstName` is required., organizationId: Path `organizationId` is required."
}

Second request immediately shows:

{"message": "Guest with this email already exists"}

So somehow the first request fails validation AND still creates the guest.

My controller:

export async function createGuest(request) {
  try {
    const session = await getServerSession(authOptions);
    const userId = session?.user?.id;
    const organizationId = session?.user?.organizationId;

    if (!userId || !organizationId) {
      return NextResponse.json(
        { message: "Authentication required" },
        { status: 401 }
      );
    }

    const body = await request.json();
    const parsed = GuestCreateSchema.safeParse(body);

    if (!parsed.success) {
      return NextResponse.json(
        { message: "Validation failed", errors: parsed.error.flatten() },
        { status: 422 }
      );
    }

    const { guest } = await createGuestService({
      data: parsed.data,
      organizationId,
      createdByUserId: userId,
    });

    return NextResponse.json(
      { message: "Guest created successfully", guest },
      { status: 201 }
    );
  } catch (err) {
    if (err.message === "Guest with this email already exists") {
      return NextResponse.json({ message: err.message }, { status: 409 });
    }
    return NextResponse.json(
      { message: "Server error", error: String(err?.message || err) },
      { status: 500 }
    );
  }
}

Service:

export async function createGuestService({
  data,
  organizationId,
  createdByUserId,
}) {
  const existingGuest = await GuestRepository.findOne({
    organizationId,
    email: data.email.toLowerCase(),
  });

  if (existingGuest) {
    throw new Error("Guest with this email already exists");
  }

  const guestPayload = {
    organizationId,
    salutation: data.salutation || null,
    firstName: data.firstName,
    lastName: data.lastName,
    email: data.email.toLowerCase(),
    phone: data.phone || null,
    alternatePhone: data.alternatePhone || null,
    address: data.address || {},
    idType: data.idType || null,
    idNumber: data.idNumber || null,
    idIssuedCountry: data.idIssuedCountry || null,
    dateOfBirth: data.dateOfBirth || null,
    nationality: data.nationality || null,
    preferences: data.preferences || {},
    guestType: data.guestType || "individual",
    companyName: data.companyName || null,
    notes: data.notes || null,
    tags: data.tags || [],
    isVIP: data.isVIP || false,
    vipNotes: data.vipNotes || null,
    createdBy: createdByUserId,
  };

  const guest = await GuestRepository.create(guestPayload);
  return { guest };
}

My question:
Why is Mongoose creating the document even though it throws validation errors such as "Path X is required"? What causes this partial/failed validation write, and how can I prevent the document from being created when validation fails?

Any help is appreciated!

here the repository this handle's all the transcations

import Guest from "@/server/models/guestModel";
import Hotel from "@/server/models/hotel/hotelModel";
import User from "@/server/models/userModel";

const GuestRepository = {
  // Create document
  create(data, options = {}) {
    return Guest.create(data, options);
  },

  // Find one document
  findOne(query, projection = undefined, options = undefined) {
    return Guest.findOne(query, projection, options);
  },

  // Find multiple documents
  find(query, projection = null, options = undefined) {
    return Guest.find(query, projection, options);
  },

  // Find by ID
  findById(id, projection = null, options = undefined) {
    return Guest.findById(id, projection, options);
  },

  // Find by ID and update
  findByIdAndUpdate(id, update, options = {}) {
    return Guest.findByIdAndUpdate(id, update, { new: true, ...options });
  },

  // Find one and update
  findOneAndUpdate(query, update, options = {}) {
    return Guest.findOneAndUpdate(query, update, { new: true, ...options });
  },

  // Count documents
  countDocuments(query = {}) {
    return Guest.countDocuments(query);
  },

  // Delete one
  deleteOne(query) {
    return Guest.deleteOne(query);
  },

  // Delete many
  deleteMany(query) {
    return Guest.deleteMany(query);
  },
};

export default GuestRepository;
4
  • I don't see any code that throws an error with the prefix "Guest validation failed:", so where exactly is that coming from? Commented Nov 23 at 8:49
  • that one is comming from mongo db Commented Nov 26 at 12:17
  • It's coming from Mongoose, not MongoDB. But that's beside the point: somewhere in your code, a Guest document is created, but you're not showing that code anywhere. Please create a Minimal, Reproducible Example. Commented Nov 26 at 13:38
  • i added the repository layer code in the top it handle's all the transcations Commented 2 days ago

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.