calcom/cal.diy · error · NotFoundException

Calendar connection not found

Error message

Calendar connection not found

What it means

Thrown by CalendarsService.getCalendarsForConnection (calendars.service.ts:98) as NotFoundException (HTTP 404) when, after calling getCalendars(userId), no entry in connectedCalendars matches credentialId === <arg>. The credentialId either does not exist, belongs to another user, or is not a calendar credential. The method delegates to getCalendars (cached) because no targeted single-credential query exists yet.

Source

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

    });
    await this.calendarsCacheService.setConnectedAndDestinationCalendarsCache(userId, result);

    return result;
  }

  /**
   * Delegates to getCalendars() (which is cached by CalendarsCacheService) because the
   * upstream platform-libraries API only supports fetching all credentials at once —
   * a targeted single-credential query is tracked as a future optimisation.
   */
  async getCalendarsForConnection(
    userId: number,
    credentialId: number
  ): Promise<ConnectedDestinationCalendars> {
    const full = await this.getCalendars(userId);
    const conn = full.connectedCalendars.find((c) => c.credentialId === credentialId);
    if (!conn) {
      throw new NotFoundException("Calendar connection not found");
    }
    return {
      ...full,
      connectedCalendars: [conn],
    };
  }

  async getBusyTimes(
    calendarsToLoad: Calendar[],
    userId: User["id"],
    dateFrom: string,
    dateTo: string,
    timezone: string
  ) {
    const credentials = await this.getUniqCalendarCredentials(calendarsToLoad, userId);
    const composedSelectedCalendars = await this.getCalendarsWithCredentials(
      credentials,
      calendarsToLoad,

View on GitHub (pinned to 176037d0af)

Solutions

  1. Refresh the calendar list via GET /v2/calendars and use only a credentialId present in the response.
  2. If you just connected, invalidate the connected-calendars cache (server-side) before retrying.
  3. Confirm the credential belongs to the current user with checkCalendarCredentials(credentialId, userId).

Example fix

// before: passing an unverified credentialId
await api.get(`/v2/calendars/connections/${maybeStaleId}`); // 404

// after: source the id from the current list
const { data } = await api.get('/v2/calendars');
const validId = data.connectedCalendars.find(c => c.credentialId === maybeStaleId)?.credentialId;
if (!validId) throw new ClientError('credential not owned');
await api.get(`/v2/calendars/connections/${validId}`);
Defensive patterns

Strategy: validation

Validate before calling

// Source credentialId from the current list before calling the per-connection endpoint
const { data } = await api.get('/v2/calendars');
const owned = data.connectedCalendars.find(c => c.credentialId === credentialId);
if (!owned) throw new ClientError('credentialId not in your connected calendars');
await api.get(`/v2/calendars/connections/${credentialId}`);

Type guard

function isOwnedCredentialId(list, credentialId) {
  return Array.isArray(list) && list.some((c) => c?.credentialId === credentialId);
}

Try / catch

try {
  await api.get(`/v2/calendars/connections/${credentialId}`);
} catch (e) {
  if (e.response?.status === 404) {
    // refresh the list and retry with a valid id, or treat as disconnected
    await refreshCalendarList();
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: GET /v2/calendars/connections/{credentialId} (or the per-connection endpoint) with an id not owned by the user; credential deleted between list and detail; cache stale and missing the entry.

Common situations: Client holds a stale credentialId after a disconnect; typo or copy-paste of an id; cross-user id from another account.

Related errors


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