Skip to content

Bug: Duration Limits Do Not Count PENDING Bookings — Allows Over-booking When "Requires Confirmation" Is Enabled #28544

@Amitverma0509

Description

@Amitverma0509

Issue Summary

When an event type is configured with both "Requires Confirmation" and a Duration Limit (e.g. "Max 1 hour per week"), the duration limit check completely ignores bookings in PENDING status. Because unconfirmed bookings are excluded from the tally, attendees can accumulate multiple pending bookings in the same period whose combined duration far exceeds the configured cap — and all of them get confirmed when the host processes them, silently violating the limit.

This is a silent correctness bug: no error is shown at any point. Hosts only discover the problem after they have already over-confirmed, meaning they end up working more hours than their limit was meant to protect. The same issue applies to the booking count limits (checkBookingLimits) for the same reason.


Steps to Reproduce

  1. Log in to cal.com (or a self-hosted instance on main).
  2. Go to Event Types → create or edit an event type with the following settings:
    • Duration: 30 minutes
    • Requires confirmation: ON
    • Duration limit: Max 1 hour per week
  3. As an attendee (use a different browser or incognito), book three separate 30-minute slots within the same calendar week — for example Monday, Wednesday, and Friday at different times.
    • All three bookings land in PENDING status (awaiting host confirmation).
  4. As the same attendee, attempt to book a fourth 30-minute slot in the same week.
    • The booking is accepted — it should have been blocked (3 × 30 min = 90 min already exceeds the 60-min limit).
  5. As the host, go to Bookings and confirm all four pending bookings.
    • All four are confirmed: total = 2 hours, which violates the 1-hour/week limit.

Actual Results

  • The 4th (and any further) booking attempt succeeds when it should be rejected.
  • The duration limit check queries existing bookings filtered by status: ACCEPTED only — PENDING bookings are invisible to it.
  • After the host confirms all pending bookings, the actual confirmed total exceeds the configured duration limit with no error raised at any stage.
  • There is no warning to the host at confirmation time that accepting these bookings would put them over limit.

Expected Results

  • PENDING bookings represent reserved time that has not yet been formally released — they should count toward the duration limit the same way ACCEPTED bookings do.

  • When a new booking attempt would cause the combined total of ACCEPTED + PENDING bookings in the period to exceed the configured duration limit, the request should be rejected with a clear message to the attendee:

    "The maximum bookable duration of 1 hour for this week has been reached. Please try a different week."

  • The fix is narrow and low-risk: include BookingStatus.PENDING alongside BookingStatus.ACCEPTED in the status filter used by checkDurationLimits (and checkBookingLimits):

// Current (broken):
status: { in: [BookingStatus.ACCEPTED] }

// Fixed:
status: { in: [BookingStatus.ACCEPTED, BookingStatus.PENDING] }

Technical Details

  • Affected surface: Booking page (attendee-facing) + handleNewBooking server action
  • Relevant source file: packages/lib/server/checkBookingLimits.ts
    • The checkDurationLimits function builds a Prisma query filtering on status: { in: [BookingStatus.ACCEPTED] }. The same pattern exists in the checkBookingLimits function (count-based limits).
  • Why this only manifests with "Requires Confirmation": Without confirmation, all bookings go directly to ACCEPTED and are counted correctly. The gap only opens when bookings sit in PENDING long enough for a second attendee (or the same attendee) to make another booking before the host confirms.
  • Secondary impact: A malicious attendee aware of this behaviour could intentionally saturate a host's calendar with pending bookings, consuming all available capacity for a period without any of them being confirmed.
  • Node.js version: Reproducible on Node.js 18.x and 20.x.

Evidence

Reproduced on a self-hosted main branch instance (Docker Compose). Configured a 30-minute event type with "Requires Confirmation: ON" and "Max 1 hour per week" duration limit. Booked three 30-minute slots in the same week as an attendee — all three created as PENDING (verified in Prisma Studio). Attempted a fourth booking in the same week — it succeeded with no error.

Then tested the same event type with "Requires Confirmation: OFF" (bookings go straight to ACCEPTED): the third booking (which would exceed 60 minutes) was correctly blocked, confirming that the duration limit logic works for confirmed bookings but breaks when the PENDING status is in play.

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐛 bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions