From 0207109612a55d0464fd6dd7304fa677812e1aeb Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 18:03:36 -0300 Subject: [PATCH] fix: add validation for empty hosts in round robin reassignment (#22429) * fix: add validation for empty hosts in round robin reassignment - Add check for empty availableUsers array before calling getLuckyUser - Throw RoundRobinHostsUnavailableForBooking error instead of 500 error - Use existing error infrastructure with 409 status code and localized message - Prevents runtime errors when no round robin hosts are available for reassignment Co-Authored-By: joe@cal.com * fix: check eventType.hosts.length directly for empty hosts validation - Move validation to check eventType.hosts.length === 0 immediately after hosts array setup - Remove later validation after ensureAvailableUsers to catch issue earlier - Follows user feedback to check hosts array directly instead of availableUsers Co-Authored-By: joe@cal.com * fix: update translation message for round robin hosts unavailable error - Make error message clearer about event type having no hosts - Change from 'No Round Robin hosts is available for booking' to 'No hosts are available in this event type for round robin booking' Co-Authored-By: joe@cal.com * Change error for event type no hosts * fix: add ErrorCode.EventTypeNoHosts to switch statement for 400 status code Addresses GitHub comment from keithwillcode to ensure EventTypeNoHosts error returns proper 400 Bad Request status instead of defaulting to 500. Co-Authored-By: joe@cal.com --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: joe@cal.com Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> --- apps/web/public/static/locales/en/common.json | 1 + packages/features/ee/round-robin/roundRobinReassignment.ts | 5 +++++ packages/lib/errorCodes.ts | 1 + packages/lib/server/getServerErrorFromUnknown.ts | 1 + 4 files changed, 8 insertions(+) diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 0738b76b95..5bc7990ab0 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -3361,5 +3361,6 @@ "license_validation_failed": "Failed to validate license key", "license_key_saved": "License key saved successfully", "timezone_mismatch_tooltip": "You are viewing the report based on your profile timezone ({{userTimezone}}), while your browser is set to timezone ({{browserTimezone}})", + "event_type_no_hosts": "No hosts are assigned to event type", "ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑" } diff --git a/packages/features/ee/round-robin/roundRobinReassignment.ts b/packages/features/ee/round-robin/roundRobinReassignment.ts index 660e91c86b..47bf254593 100644 --- a/packages/features/ee/round-robin/roundRobinReassignment.ts +++ b/packages/features/ee/round-robin/roundRobinReassignment.ts @@ -20,6 +20,7 @@ import { enrichHostsWithDelegationCredentials, enrichUserWithDelegationCredentialsIncludeServiceAccountKey, } from "@calcom/lib/delegationCredential/server"; +import { ErrorCode } from "@calcom/lib/errorCodes"; import { getEventName } from "@calcom/lib/event"; import { IdempotencyKeyService } from "@calcom/lib/idempotencyKey/idempotencyKeyService"; import { isPrismaObjOrUndefined } from "@calcom/lib/isPrismaObj"; @@ -99,6 +100,10 @@ export const roundRobinReassignment = async ({ createdAt: new Date(0), // use earliest possible date as fallback })); + if (eventType.hosts.length === 0) { + throw new Error(ErrorCode.EventTypeNoHosts); + } + const roundRobinHosts = eventType.hosts.filter((host) => !host.isFixed); const originalOrganizer = booking.user; diff --git a/packages/lib/errorCodes.ts b/packages/lib/errorCodes.ts index 6f7cb7f056..b96691491e 100644 --- a/packages/lib/errorCodes.ts +++ b/packages/lib/errorCodes.ts @@ -23,4 +23,5 @@ export enum ErrorCode { BookerLimitExceededReschedule = "booker_limit_exceeded_error_reschedule", BookingNotAllowedByRestrictionSchedule = "booking_not_allowed_by_restriction_schedule_error", RestrictionScheduleNotFound = "restriction_schedule_not_found_error", + EventTypeNoHosts = "event_type_no_hosts", } diff --git a/packages/lib/server/getServerErrorFromUnknown.ts b/packages/lib/server/getServerErrorFromUnknown.ts index abafecdcfc..df5b63f5a4 100644 --- a/packages/lib/server/getServerErrorFromUnknown.ts +++ b/packages/lib/server/getServerErrorFromUnknown.ts @@ -111,6 +111,7 @@ function getStatusCode(cause: Error | ErrorWithCode): number { case ErrorCode.BookingNotAllowedByRestrictionSchedule: case ErrorCode.BookerLimitExceeded: case ErrorCode.BookerLimitExceededReschedule: + case ErrorCode.EventTypeNoHosts: return 400; // 409 Conflict case ErrorCode.NoAvailableUsersFound: