When a slot reaches capacity and the system throws an unhandled database constraint violation or returns an HTTP 500, the customer receives no actionable information: they cannot retry a different slot, join a waitlist, or understand what happened. An unhandled capacity error produces the same symptom as a server crash from the user's perspective. Even without a formal waitlist feature, returning a structured 409 with a descriptive message gives the frontend enough information to guide the user — a minimum viable response to a predictable state the system already knows about.
Low because the primary impact is poor user experience and support volume, not data corruption or security exposure, when capacity limits are reached.
Handle the capacity-exceeded case explicitly in your booking handler (e.g., src/app/api/bookings/route.ts). Return a 409 with a structured body so the frontend can render a useful message.
if (currentCount >= slot.maxCapacity) {
// If waitlist is supported:
if (req.body.joinWaitlist) {
await db.waitlistEntry.create({ data: { slotId, userId } });
return res.status(202).json({ status: 'waitlisted' });
}
return res.status(409).json({
code: 'SLOT_FULL',
message: 'This slot is fully booked.',
});
}
ID: booking-flow-lifecycle.double-booking.waitlist-handling
Label: Waitlist handling
Severity: low
What to look for: Logic that handles the "full/at capacity" state. Count all code paths that return a "slot full" or "at capacity" response. For each path, verify: (1) a user-friendly error message is returned (not a generic 500 or unhandled exception), and (2) if a waitlist feature exists, users are offered the option to join it. Look for a Waitlist model, waitlist table, or joinWaitlist parameter. Enumerate: "X capacity-exceeded paths found; Y return user-friendly responses."
Pass criteria: At least 1 explicit handling path for full capacity exists. The response must include a clear, user-facing message (HTTP 409 or 422 with descriptive body, not 500). If waitlist functionality exists, it must be offered when capacity is reached. Report: "X of Y capacity-exceeded paths return user-friendly responses. Waitlist: [available in file:line | not implemented]."
Fail criteria: System crashes, throws generic 500 error, or behaves unpredictably when a slot reaches capacity. An unhandled exception from a database constraint violation also fails.
Skip (N/A) when: Requirements do not include or mention waitlist functionality AND no capacity limits exist (strictly 1:1 bookings with UNIQUE constraint that prevents overbooking at DB level).
Detail on fail: "When a slot is full, the system returns a generic 500 error instead of a user-friendly message or waitlist option."
Cross-reference: The overbooking-prevention check in Booking Creation verifies the capacity comparison logic that triggers this handling.
Cross-reference: The concurrent-request-handling check in this category ensures the UNIQUE constraint that triggers capacity errors is handled gracefully.
Cross-reference: The status-updates check in Lifecycle Management verifies waitlist promotion notifications when cancellations free slots.
Remediation: Implement structured full-capacity handling in your booking handler (e.g., src/app/api/bookings/route.ts).
if (currentCount >= slot.maxCapacity) {
if (req.body.joinWaitlist) {
await db.waitlist.create({ slotId, userId });
return res.json({ status: 'waitlist', message: 'Added to waitlist' });
}
throw new Error("Slot is full");
}