calcom/cal.diy · error · UnauthorizedException

Google Calendar credentials are invalid. Please reconnect.

Error message

Google Calendar credentials are invalid. Please reconnect.

What it means

Thrown by getCalendarClientForUser when a google_calendar credential exists but its invalid boolean flag is true. The invalid flag is set by Cal.com's sync engine when Google rejects the stored refresh token (revoked, expired, app access revoked). Returns HTTP 401. Distinct from error 81: the row exists but is marked unusable.

Source

Thrown at apps/api/v2/src/modules/cal-unified-calendars/services/google-calendar.service.ts:180

    } catch (error) {
      return null;
    }
  }

  /**
   * Gets an authorized Google Calendar instance for the given user (for user-scoped list/create/delete).
   * Tries delegated auth first (if available), then falls back to direct OAuth.
   */
  async getCalendarClientForUser(userId: number): Promise<calendar_v3.Calendar> {
    const credential = await this.credentialsRepository.findCredentialWithDelegationByTypeAndUserId(
      GOOGLE_CALENDAR_TYPE,
      userId
    );
    if (!credential) {
      throw new UnauthorizedException("Google Calendar is not connected for this user");
    }
    if (credential.invalid) {
      throw new UnauthorizedException("Google Calendar credentials are invalid. Please reconnect.");
    }
    return this.getAuthorizedCalendarInstance(
      credential.user?.email ?? undefined,
      credential.key,
      credential.delegationCredentialId ? { id: credential.delegationCredentialId } : null
    );
  }

  /**
   * Gets an authorized Google Calendar instance for a specific credential (connection).
   * Tries delegated auth first (if available), then falls back to direct OAuth.
   */
  async getCalendarClientByCredentialId(userId: number, credentialId: number): Promise<calendar_v3.Calendar> {
    const credential = await this.credentialsRepository.findCredentialByIdAndUserId(credentialId, userId);
    if (!credential) {
      throw new NotFoundException("Calendar connection not found");
    }
    if (credential.type !== GOOGLE_CALENDAR_TYPE) {

View on GitHub (pinned to 176037d0af)

Solutions

  1. Direct the user to reconnect Google Calendar through the OAuth flow, which upserts a fresh credential row with invalid=false.
  2. Before the call, check credential.invalid and short-circuit with a 'reconnect' instruction.
  3. Audit recent sync logs for the credential to see why invalid was set (token refresh failure).
  4. If using delegation, confirm the delegated service account still has Calendar API access in Workspace admin.

Example fix

// before
const cal = await googleCalendarService.getCalendarClientForUser(userId);

// after
const cred = await credentialsRepository.findCredentialWithDelegationByTypeAndUserId(GOOGLE_CALENDAR_TYPE, userId);
if (cred?.invalid) {
  throw new UnauthorizedException('Google Calendar token revoked — please reconnect at /apps/google-calendar.');
}
Defensive patterns

Strategy: validation

Validate before calling

async function googleCalendarIsUsable(userId: number): Promise<boolean> {
  const cred = await credentialsRepository.findCredentialWithDelegationByTypeAndUserId(GOOGLE_CALENDAR_TYPE, userId);
  return Boolean(cred && !cred.invalid);
}

if (!(await googleCalendarIsUsable(userId))) {
  return { code: 'reconnect_google_calendar' };
}

Type guard

function isUsableCredential<T extends { invalid?: boolean }>(c: T | null): c is T {
  return c !== null && c.invalid !== true;
}

Try / catch

try {
  const cal = await googleCalendarService.getCalendarClientForUser(userId);
} catch (e) {
  if (e instanceof UnauthorizedException && /invalid/i.test(e.message)) {
    // token revoked — push reconnect notification
    await notifyUser(userId, 'google_calendar_revoked');
    throw new ApiError('reconnect_required', 422);
  }
  throw e;
}

Prevention

When it happens

Trigger: The user revoked Calendar access from their Google account security page; the refresh token expired after 6 months of inactivity; an admin revoked the OAuth client; a failed sync set invalid=true and the user then calls any user-scoped calendar operation.

Common situations: Long-inactive user returning; Google Workspace admin disabled the app; password change on the Google account invalidating tokens; stale test credentials.

Related errors


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