calcom/cal.diy · error · NotFoundException

Could not find calendar ${externalId}

Error message

Could not find calendar ${externalId}

What it means

Thrown by DestinationCalendarsService.updateCalendar when no delegationCredentialId is provided AND no matching calendar is found among the user's connected calendars for the given externalId+integration (with readOnly=false). The lookup runs getCalendars(userId) then searches for cal.externalId === externalId && cal.integration === integration && cal.readOnly === false to obtain credentialId; a miss raises NotFoundException (HTTP 404).

Source

Thrown at apps/api/v2/src/modules/destination-calendars/services/destination-calendars.service.ts:31

  ) {}

  async updateDestinationCalendars(
    integration: string,
    externalId: string,
    userId: number,
    delegationCredentialId?: string
  ) {
    const userCalendars = await this.calendarsService.getCalendars(userId);
    const allCalendars: Calendar[] = userCalendars.connectedCalendars
      .map((cal: ConnectedCalendar) => cal.calendars ?? [])
      .flat();
    const credentialId = allCalendars.find(
      (cal: Calendar) =>
        cal.externalId === externalId && cal.integration === integration && cal.readOnly === false
    )?.credentialId;

    if (!delegationCredentialId && !credentialId) {
      throw new NotFoundException(`Could not find calendar ${externalId}`);
    }

    const delegatedCalendar = delegationCredentialId
      ? allCalendars.find(
          (cal: Calendar) =>
            cal.externalId === externalId &&
            cal.integration === integration &&
            cal.delegationCredentialId === delegationCredentialId
        )
      : undefined;

    if (delegationCredentialId && !delegatedCalendar) {
      throw new NotFoundException(`Could not find calendar ${externalId}`);
    }

    const primaryEmail = delegatedCalendar
      ? (delegatedCalendar.primary && delegatedCalendar?.email) || undefined
      : allCalendars.find((cal: Calendar) => cal.primary && cal.credentialId === credentialId)?.email;

View on GitHub (pinned to 176037d0af)

Solutions

  1. Re-fetch the user's connected calendars (GET /calendars) and pass a current externalId + matching integration.
  2. If the target is a delegated calendar, pass the correct delegationCredentialId so the second lookup path is used instead.
  3. Confirm the calendar is not read-only for the credential you expect to write with.
Defensive patterns

Strategy: validation

Validate before calling

const userCalendars = await calendarsService.getCalendars(userId);
const all = userCalendars.connectedCalendars.flatMap(c => c.calendars ?? []);
const match = all.find(c => c.externalId === externalId && c.integration === integration && !c.readOnly);
if (!match && !delegationCredentialId) {
  throw new NotFoundException(`Could not find calendar ${externalId}`);
}
await destinationCalendarsService.updateCalendar(userId, integration, externalId, delegationCredentialId);

Type guard

const isWritableCalendar = (c: Calendar): boolean =>
  !!c.externalId && !!c.integration && c.readOnly === false;

Prevention

When it happens

Trigger: PUT/PATCH to update a destination calendar with an externalId that the user does not own, that belongs to a different integration, that is read-only, or that no longer exists in the connected calendar list. Without delegationCredentialId, the credentialId search must succeed or this throws.

Common situations: externalId from a stale frontend cache; calendar renamed/moved on the provider side; integration mismatch (passing a Google calendar id for an Office365 integration); calendar is a read-only delegated calendar but delegationCredentialId was not passed.

Related errors


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