calcom/cal.diy · warning · NotFoundException

No SelectedCalendar found.

Error message

No SelectedCalendar found.

What it means

NotFoundException (HTTP 404) thrown by SelectedCalendarsService when deleting a user selected calendar and the underlying repository reports NO_SELECTED_CALENDAR_FOUND. The repository's removeUserSelectedCalendar raises this when no row matches the (userId, integration, externalId) tuple, and the service translates the string message into a 404.

Source

Thrown at apps/api/v2/src/modules/selected-calendars/services/selected-calendars.service.ts:58

    selectedCalendar: SelectedCalendarsQueryParamsInputDto,
    user: UserWithProfile
  ) {
    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

  1. Before deleting, confirm the calendar still appears in GET /v2/selected-calendars for the user.
  2. Treat a 404 on delete as a success if your goal is simply 'ensure it is gone' (idempotent delete).
  3. Verify the integration key and externalId exactly match the values returned by the list endpoint.

Example fix

// before
await api.delete(`/selected-calendars/${integration}/${externalId}`);
// after — idempotent removal
try {
  await api.delete(`/selected-calendars/${integration}/${externalId}`);
} catch (e) {
  if (e.status !== 404) throw e; // already gone is fine
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function removeCalendarIdempotent(userId: number, integration: string, externalId: string) {
  const list = await api.get('/selected-calendars', { params: { userId } });
  const exists = list.some((c: { integration: string; externalId: string }) =>
    c.integration === integration && c.externalId === externalId);
  if (!exists) return; // already gone
  return api.delete(`/selected-calendars/${integration}/${externalId}`);
}

Type guard

const isExistingCalendar = (list: { integration: string; externalId: string }[], integration: string, externalId: string): boolean =>
  list.some(c => c.integration === integration && c.externalId === externalId);

Try / catch

try { await api.delete(`/selected-calendars/${integration}/${externalId}`); }
catch (e) { if (e.status !== 404) throw e; /* already removed — ok */ }

Prevention

When it happens

Trigger: DELETE /v2/selected-calendars with an integration+externalId pair that the user never connected, or already removed; a sync process trying to remove a calendar that was deleted by another client in the meantime.

Common situations: Stale UI list still showing a calendar the user disconnected elsewhere; webhook firing twice for the same calendar removal; integration name mismatch (e.g. 'google_calendar' vs 'google') or externalId drift after re-auth.

Related errors


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