calcom/cal.diy · error · BadRequestException

Booking with bookingUid=${bookingUid} is not part of a recur

Error message

Booking with bookingUid=${bookingUid} is not part of a recurring booking.

What it means

Thrown by getAllRecurringBookingsByIndividualUid when the booking identified by bookingUid has no recurringEventId — i.e. it is a standalone booking, not part of a recurring series. Triggered when cancelSubsequentBookings is requested on a non-recurring booking. BadRequestException (HTTP 400).

Source

Thrown at apps/api/v2/src/platform/bookings/2024-08-13/services/bookings.service.ts:938

      arePlatformEmailsEnabled: bookingRequest.arePlatformEmailsEnabled,
      platformClientId: bookingRequest.platformClientId,
      platformCancelUrl: bookingRequest.platformCancelUrl,
      platformRescheduleUrl: bookingRequest.platformRescheduleUrl,
      platformBookingUrl: bookingRequest.platformBookingUrl,
    });

    if ("cancelSubsequentBookings" in body && body.cancelSubsequentBookings) {
      return this.getAllRecurringBookingsByIndividualUid(bookingUid, authUser);
    }

    return this.getBooking(bookingUid, authUser);
  }

  private async getAllRecurringBookingsByIndividualUid(bookingUid: string, authUser: AuthOptionalUser) {
    const booking = await this.bookingsRepository.getByUid(bookingUid);
    const recurringBookingUid = booking?.recurringEventId;
    if (!recurringBookingUid) {
      throw new BadRequestException(
        `Booking with bookingUid=${bookingUid} is not part of a recurring booking.`
      );
    }

    return await this.getBooking(recurringBookingUid, authUser);
  }

  async markAbsent(
    bookingUid: string,
    bookingOwnerId: number,
    body: MarkAbsentBookingInput_2024_08_13,
    userUuid: string
  ) {
    const bodyTransformed = this.inputService.transformInputMarkAbsentBooking(body);
    const bookingBefore = await this.bookingsRepository.getByUid(bookingUid);

    if (!bookingBefore) {
      throw new NotFoundException(`Booking with uid=${bookingUid} not found.`);

View on GitHub (pinned to 176037d0af)

Solutions

  1. Only set cancelSubsequentBookings when the booking's recurringEventId is non-null.
  2. Fetch the booking first and branch: if recurringEventId present, allow bulk; else single cancel.
  3. Update event type to enable recurring schedules if bulk cancel is required.

Example fix

// before
await client.delete(`/v2/bookings/${uid}`, { data: { cancelSubsequentBookings: true } });
// after
const b = await client.get(`/v2/bookings/${uid}`);
await client.delete(`/v2/bookings/${uid}`, { data: { cancelSubsequentBookings: !!b.recurringEventId } });
Defensive patterns

Strategy: validation

Validate before calling

const b = await client.get(`/v2/bookings/${uid}`);
if (!b.recurringEventId) throw new Error('Booking is not recurring; cannot cancel subsequent');

Type guard

function isRecurring(b: { recurringEventId?: string | null }): boolean {
  return !!b.recurringEventId;
}

Try / catch

try { await client.delete(`/v2/bookings/${uid}`, { data: { cancelSubsequentBookings: true } }); }
catch (e) {
  if (e.status === 400 && /not part of a recurring/i.test(e.message)) { /* retry without the flag */ }
  else throw e;
}

Prevention

When it happens

Trigger: A cancel or fetch request with cancelSubsequentBookings=true (or equivalent recurring expansion) on a booking that is not a member of a recurring series.

Common situations: UI offers 'cancel all subsequent' for non-recurring bookings; logic assumes recurring based on event type but the booking was created as a single instance.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/acb80704e3870d74. Report an issue: GitHub.