calcom/cal.diy · error · UnauthorizedException

Google Calendar not connected.

Error message

Google Calendar not connected.

What it means

Thrown by GoogleCalendarService.checkIfCalendarConnected (gcal.service.ts:119) as UnauthorizedException (HTTP 401) when the credential exists and is valid but calendarsService.getCalendars(userId) returns no connected calendar of type google_calendar. The credential is stored but no Google calendar is surfaced/linked. Mirror of error 362.

Source

Thrown at apps/api/v2/src/platform/calendars/services/gcal.service.ts:119

    const gcalCredentials = await this.credentialRepository.findCredentialByTypeAndUserId(
      "google_calendar",
      userId
    );

    if (!gcalCredentials) {
      throw new BadRequestException("Credentials for google_calendar not found.");
    }

    if (gcalCredentials.invalid) {
      throw new BadRequestException("Invalid google OAuth credentials.");
    }

    const { connectedCalendars } = await this.calendarsService.getCalendars(userId);
    const googleCalendar = connectedCalendars.find(
      (cal: { integration: { type: string } }) => cal.integration.type === GOOGLE_CALENDAR_TYPE
    );
    if (!googleCalendar) {
      throw new UnauthorizedException("Google Calendar not connected.");
    }
    if (googleCalendar.error?.message) {
      throw new UnauthorizedException(googleCalendar.error?.message);
    }

    return { status: SUCCESS_STATUS };
  }

  async saveCalendarCredentialsAndRedirect(
    code: string,
    accessToken: string,
    origin: string,
    redir?: string,
    isDryRun?: boolean
  ) {
    // User chose not to authorize your app or didn't authorize your app
    // redirect directly without oauth code
    if (!code || code === "undefined") {

View on GitHub (pinned to 176037d0af)

Solutions

  1. Invalidate the connected-calendars cache for the user and retry check.
  2. Re-run the save callback so createAndLinkCalendarEntry links the primary calendar.
  3. Confirm a SelectedCalendars row exists for the google primary calendar externalId + credentialId.

Example fix

// before: check right after save returns 401 (stale cache / not linked)
await api.get('/v2/calendars/google_calendar/check'); // 401

// after: clear cache server-side then re-check
calendarsCacheService.deleteConnectedAndDestinationCalendarsCache(userId);
await api.get('/v2/calendars/google_calendar/check'); // 200 once linked
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the google calendar is linked (after cache refresh) before check
const { data } = await api.get('/v2/calendars', { params: { ensureDefaultSelectedCalendars: true } });
const linked = data.connectedCalendars.some(c => c.integration?.type === 'google_calendar');
if (!linked) throw new Error('Google calendar did not link — re-run save');

Type guard

function hasConnectedGoogle(list) {
  return Array.isArray(list) && list.some(c => c?.integration?.type === 'google_calendar');
}

Try / catch

try {
  await api.get('/v2/calendars/google_calendar/check');
} catch (e) {
  if (e.response?.status === 401 && /not connected/i.test(e.response?.data?.message)) {
    // re-run save callback to link the primary calendar, then retry once
    await reRunGoogleSaveCallback();
    return api.get('/v2/calendars/google_calendar/check');
  }
  throw e;
}

Prevention

When it happens

Trigger: OAuth completed but the primary calendar was never linked (saveCalendarCredentialsAndRedirect didn't reach createAndLinkCalendarEntry); cache stale; selectedCalendars row missing for the primary calendar id.

Common situations: Save flow returned early (no primaryCal.id, or alreadyExistingSelectedCalendar branch); cache not invalidated after connect; race between save and check.

Related errors


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