calcom/cal.diy · error · BadRequestException
Multiple SelecteCalendars found. Skipping deletion
Error message
Multiple SelecteCalendars found. Skipping deletion
What it means
BadRequestException (HTTP 400) thrown when the repository reports MULTIPLE_SELECTED_CALENDARS_FOUND during deletion. removeUserSelectedCalendar expects to remove exactly one row; finding two or more rows for the same (userId, integration, externalId) is an inconsistent state, so the service refuses to delete ambiguously rather than guessing which row.
Source
Thrown at apps/api/v2/src/modules/selected-calendars/services/selected-calendars.service.ts:60
) {
const { integration, externalId, credentialId } = selectedCalendar;
await this.calendarsService.checkCalendarCredentials(Number(credentialId), user.id);
try {
const removedCalendarEntry = await this.selectedCalendarsRepository.removeUserSelectedCalendar(
user.id,
integration,
externalId,
undefined
);
await this.calendarsCacheService.deleteConnectedAndDestinationCalendarsCache(user.id);
return removedCalendarEntry;
} catch (error) {
if (error instanceof Error) {
if (error.message === NO_SELECTED_CALENDAR_FOUND) {
throw new NotFoundException(NO_SELECTED_CALENDAR_FOUND);
} else if (error.message === MULTIPLE_SELECTED_CALENDARS_FOUND) {
throw new BadRequestException(MULTIPLE_SELECTED_CALENDARS_FOUND);
} else {
throw new InternalServerErrorException(error.message);
}
}
throw new InternalServerErrorException(
"An unexpected error occurred while deleting the selected calendar"
);
}
}
}
View on GitHub (pinned to 176037d0af)
Solutions
- Investigate and deduplicate the rows in the database (keep one, delete the rest) so deletion is unambiguous.
- Add a unique constraint on (userId, integration, externalId) if missing, to prevent recurrence.
- Temporarily delete by id or with a bulk delete to clear the duplicates, then retry the normal endpoint.
Example fix
// before — normal delete fails on duplicates
await api.delete(`/selected-calendars/${integration}/${externalId}`); // 400
// after — dedupe via admin/DB, then retry
// SQL: DELETE FROM "SelectedCalendar" WHERE id IN (SELECT id FROM ... GROUP BY ... HAVING COUNT(*)>1);
await api.delete(`/selected-calendars/${integration}/${externalId}`); Defensive patterns
Strategy: validation
Validate before calling
async function assertSingleCalendarRow(userId: number, integration: string, externalId: string) {
const rows = await api.get('/selected-calendars', { params: { userId, integration, externalId } });
if (rows.length > 1) throw new Error(`Duplicate rows (${rows.length}); dedupe before deleting`);
} Type guard
const hasUniqueCalendars = (rows: { integration: string; externalId: string }[]): boolean => {
const seen = new Set<string>();
return rows.every(r => { const k = `${r.integration}:${r.externalId}`; if (seen.has(k)) return false; seen.add(k); return true; });
}; Try / catch
try { await api.delete(`/selected-calendars/${integration}/${externalId}`); }
catch (e) { if (/multiple selectedcalendars/i.test(e.message)) { /* run dedupe, then retry */ } else throw e; } Prevention
- Add a unique constraint on (userId, integration, externalId) to prevent duplicate rows.
- Periodically audit for duplicate SelectedCalendar rows.
- Use upsert (not insert) when connecting calendars.
When it happens
Trigger: DELETE /v2/selected-calendars when the database contains duplicate SelectedCalendar rows for the same user/integration/externalId — typically from a past bug, a missing unique constraint, or a non-atomic upsert that inserted twice.
Common situations: Legacy data created before a unique constraint was added; concurrent connect flows racing to insert the same calendar; a manual DB import that duplicated rows.
Related errors
- Booking with uid ${uid} not found
- Event type with uid ${uid} not found
- No users found or no team present for event type with uid ${
- Could not set ${app} as default conferencing app
- Google Meet is already connected for this user.
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/cdb7122d4d06fe72.
Report an issue: GitHub.