calcom/cal.diy · error · BadRequestException

Invalid office 365 calendar credentials.

Error message

Invalid office 365 calendar credentials.

What it means

In OutlookService.checkIfCalendarConnected, after the office365_calendar credential is found it is checked for the `invalid` flag. Cal.com flips this flag when a prior Microsoft Graph call failed (revoked refresh token, consent withdrawn, deleted mailbox). A truthy invalid short-circuits with BadRequestException('Invalid office 365 calendar credentials.') rather than attempting the live getCalendars enumeration.

Source

Thrown at apps/api/v2/src/platform/calendars/services/outlook.service.ts:99

    const query = stringify(params);

    const url = `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?${query}`;

    return url;
  }

  async checkIfCalendarConnected(userId: number): Promise<{ status: typeof SUCCESS_STATUS }> {
    const office365CalendarCredentials = await this.credentialRepository.findCredentialByTypeAndUserId(
      "office365_calendar",
      userId
    );

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

    if (office365CalendarCredentials.invalid) {
      throw new BadRequestException("Invalid office 365 calendar credentials.");
    }

    const { connectedCalendars } = await this.calendarsService.getCalendars(userId);
    const office365Calendar = connectedCalendars.find(
      (cal: { integration: { type: string } }) => cal.integration.type === OFFICE_365_CALENDAR_TYPE
    );
    if (!office365Calendar) {
      throw new UnauthorizedException("Office 365 calendar not connected.");
    }
    if (office365Calendar.error?.message) {
      throw new UnauthorizedException(office365Calendar.error?.message);
    }

    return {
      status: SUCCESS_STATUS,
    };
  }

View on GitHub (pinned to 176037d0af)

Solutions

  1. Re-run the Office 365 connect flow; a fresh OAuth code will replace the credential and clear invalid.
  2. In the Microsoft account, confirm the Cal app registration still has consent and the required delegated scopes (offline_access, Calendars.Read, Calendars.ReadWrite).
  3. If this is an enterprise tenant, verify the admin hasn't disabled or removed the app registration.
Defensive patterns

Strategy: validation

Validate before calling

const cred = await credentialRepository.findCredentialByTypeAndUserId('office365_calendar', userId);
if (cred?.invalid) {
  // prompt reconnect rather than calling /check
}

Try / catch

try {
  await outlookService.checkIfCalendarConnected(userId);
} catch (e) {
  if (e instanceof BadRequestException && e.message === 'Invalid office 365 calendar credentials.') {
    // re-run the Office 365 connect flow
  } else throw e;
}

Prevention

When it happens

Trigger: User revoked app consent in the Microsoft account (https://account.activedirectory.windowsazure.com); the refresh token expired (90-day inactivity) and a refresh attempt failed enough times to mark invalid; admin removed the enterprise app; Graph API permission scopes were reduced so existing tokens no longer work.

Common situations: Long-dormant O365 integration; tenant admin revoked the app registration; consent was granted for personal account then user switched to a work account; scopes mismatch between the app registration and what Cal requests (offline_access, Calendars.Read, Calendars.ReadWrite per getOAuthCredentials).

Related errors


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