calcom/cal.diy · error · UnauthorizedException

Calendar credentials are invalid. Please reconnect.

Error message

Calendar credentials are invalid. Please reconnect.

What it means

Connection-scoped counterpart of error 82. Thrown by getCalendarClientByCredentialId when the credential exists, is google_calendar, but invalid is true. Returns HTTP 401. Means the credential was marked unusable by a prior failed sync.

Source

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

    );
  }

  /**
   * 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) {
      throw new BadRequestException(
        "Event operations for this connection are currently only available for Google Calendar"
      );
    }
    if (credential.invalid) {
      throw new UnauthorizedException("Calendar credentials are invalid. Please reconnect.");
    }
    return this.getAuthorizedCalendarInstance(
      credential.user?.email ?? undefined,
      credential.key,
      credential.delegationCredentialId ? { id: credential.delegationCredentialId } : null
    );
  }

  // ─── Shared private helpers (DRY calendar CRUD) ──────────────────────

  private async listEventsWithClient(
    calendar: calendar_v3.Calendar,
    calendarId: string,
    timeMin: string,
    timeMax: string
  ): Promise<GoogleCalendarEventResponse[]> {
    const effectiveCalendarId = calendarId || "primary";
    try {

View on GitHub (pinned to 176037d0af)

Solutions

  1. Reconnect Google Calendar to obtain a fresh credential, then use the new connectionId.
  2. Pre-check the connection's status field from the connections list and block the action when invalid.
  3. If reconnecting yields a new credentialId, update any stored references in client state.
  4. Inspect sync logs for why invalid was set on this credential.

Example fix

// before
const cal = await googleCalendarService.getCalendarClientByCredentialId(userId, credentialId);

// after
const cred = await credentialsRepository.findCredentialByIdAndUserId(credentialId, userId);
if (cred?.invalid) {
  return { status: 'error', code: 'credential_invalid', action: 'reconnect_google_calendar' };
}
Defensive patterns

Strategy: validation

Validate before calling

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

if (!(await connectionIsUsable(credentialId, userId))) {
  return { code: 'reconnect_google_calendar', connectionId };
}

Type guard

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

Try / catch

try {
  await googleCalendarService.listEventsForUserByConnectionId(userId, credentialId, calId, t0, t1);
} catch (e) {
  if (e instanceof UnauthorizedException && /invalid/i.test(e.message)) {
    return res.status(422).json({ code: 'credential_invalid', connectionId });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling /v2/calendars/connections/{connectionId}/events with a connectionId whose underlying Google credential has invalid=true (refresh token revoked or refresh failed during a prior sync).

Common situations: Same root causes as 82 but reached via the connection-scoped API surface; the user reconnected and got a new credential row but the client still references the old connectionId.

Related errors


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