calcom/cal.diy · error · BadRequestException
Can't cancel booking with uid=${bookingUid} because it has b
Error message
Can't cancel booking with uid=${bookingUid} because it has been cancelled already. Please provide uid of a booking that is not cancelled. What it means
cancelBooking checks bookingInfo.status === 'CANCELLED' and throws BadRequestException (HTTP 400). Cancelling an already-cancelled booking is not permitted; the caller must supply the uid of an active booking.
Source
Thrown at apps/api/v2/src/platform/bookings/2024-04-15/controllers/bookings.controller.ts:255
@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,
userUuid: bookingRequest.userUuid,
arePlatformEmailsEnabled: bookingRequest.arePlatformEmailsEnabled,
platformClientId: bookingRequest.platformClientId,
platformCancelUrl: bookingRequest.platformCancelUrl,
platformRescheduleUrl: bookingRequest.platformRescheduleUrl,
platformBookingUrl: bookingRequest.platformBookingUrl,
actionSource: "API_V2",
});
return {View on GitHub (pinned to 176037d0af)
Solutions
- Fetch the booking status first and skip cancel if already CANCELLED.
- Make cancel idempotent client-side by treating 'already cancelled' (HTTP 400 with this message) as success.
- Disable the cancel action in the UI once status is CANCELLED.
Example fix
// before await api.cancelBooking(uid); // after const b = await api.getBooking(uid); if (b.status === 'CANCELLED') return; // idempotent await api.cancelBooking(uid);
Defensive patterns
Strategy: validation
Validate before calling
async function cancelIfActive(api, uid) {
const b = await api.getBooking(uid);
if (b.status === 'CANCELLED') return; // idempotent
return api.cancelBooking(uid);
} Type guard
const isAlreadyCancelled = (b: { status: string }): boolean =>
b.status === 'CANCELLED'; Try / catch
try { await api.cancelBooking(uid); }
catch (e) {
if (e.status === 400 && /has been cancelled already/.test(e.message)) return; // idempotent
throw e;
} Prevention
- Check booking status before cancelling and skip when CANCELLED.
- Treat the 'already cancelled' message as success in retry logic.
- Disable the cancel action once status flips to CANCELLED.
When it happens
Trigger: POST /:bookingUid/cancel for a booking whose status is already 'CANCELLED'.
Common situations: Double-submit; retry after a successful cancel; UI not refreshing booking state; concurrent cancel requests.
Related errors
- Please provide booking uid instead of booking id.
- User with id=${userId} has already authorized client with id
- Booking ID is required.
- Invalid seatUid: this seat does not exist or has already bee
- Invalid seatUid: this seat does not belong to this booking.
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/df593d969afe98f5.
Report an issue: GitHub.