calcom/cal.diy · error · BadRequestException

Please provide booking uid instead of booking id.

Error message

Please provide booking uid instead of booking id.

What it means

cancelBooking computes isUidNumber = !Number.isNaN(Number(bookingUid)); if the route param parses as a number it throws BadRequestException (HTTP 400) telling the caller to send a booking uid, not a numeric booking id. Booking uids are string identifiers; numeric ids are a different column.

Source

Thrown at apps/api/v2/src/platform/bookings/2024-04-15/controllers/bookings.controller.ts:246

    } catch (err) {
      this.handleBookingErrors(err);
    }
    throw new InternalServerErrorException("Could not create booking.");
  }

  @Post("/:bookingUid/cancel")
  async cancelBooking(
    @Req() req: BookingRequest,
    @Param("bookingUid") bookingUid: string,
    @Body() _body: CancelBookingInput_2024_04_15,
    @Headers(X_CAL_CLIENT_ID) clientId?: string,
    @Headers(X_CAL_PLATFORM_EMBED) isEmbed?: string
  ): Promise<ApiResponse<{ bookingId: number; bookingUid: string; onlyRemovedAttendee: boolean }>> {
    const oAuthClientId = clientId?.toString();
    const isUidNumber = !Number.isNaN(Number(bookingUid));

    if (isUidNumber) {
      throw new BadRequestException("Please provide booking uid instead of booking id.");
    }

    if (bookingUid) {
      const { bookingInfo } = await getBookingInfo(bookingUid);
      if (!bookingInfo) {
        throw new NotFoundException(`Booking with UID=${bookingUid} does not exist.`);
      }
      if (bookingInfo.status === "CANCELLED") {
        throw new BadRequestException(
          `Can't cancel booking with uid=${bookingUid} because it has been cancelled already. Please provide uid of a booking that is not cancelled.`
        );
      }
      try {
        req.body.uid = bookingUid;
        const bookingRequest = await this.createNextApiBookingRequest(req, oAuthClientId, undefined, isEmbed);
        const res = await handleCancelBooking({
          bookingData: bookingRequest.body,
          userId: bookingRequest.userId,

View on GitHub (pinned to 176037d0af)

Solutions

  1. Use booking.uid (string), not booking.id (number), in the cancel path.
  2. Audit response mapping to surface uid as the canonical identifier.
  3. Add a client-side guard: if /^\d+$/.test(bookingUid) reject before sending.

Example fix

// before
await api.cancelBooking(String(booking.id));
// after
await api.cancelBooking(booking.uid);
Defensive patterns

Strategy: validation

Validate before calling

function assertBookingUid(uid: string) {
  if (typeof uid !== 'string' || /^\d+$/.test(uid)) {
    throw new Error('Provide booking.uid (string), not booking.id (numeric)');
  }
}
assertBookingUid(bookingUid);

Type guard

const isBookingUidNotNumericId = (v: unknown): v is string =>
  typeof v === 'string' && v.length > 0 && !/^\d+$/.test(v);

Try / catch

try { await api.cancelBooking(uid); }
catch (e) {
  if (e.status === 400 && /booking uid instead of booking id/.test(e.message)) {
    // re-resolve uid from booking object and retry
  } else throw e;
}

Prevention

When it happens

Trigger: POST /:bookingUid/cancel where :bookingUid is purely numeric (e.g. '12345' — the booking id) instead of the uid string (e.g. 'a1b2c3...').

Common situations: Client used booking.id from a response instead of booking.uid; UI label confusion; migration from an older API that used numeric ids.

Related errors


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