calcom/cal.diy · error · UnauthorizedException

Ics Feed not connected.

Error message

Ics Feed not connected.

What it means

After the ICS credential is found and not flagged invalid, IcsFeedService.check calls calendarsService.getCalendars(userId) and searches connectedCalendars for an entry whose integration.type === ICS_CALENDAR_TYPE. If none is present, the credential exists but is not wired into the user's connected-calendars list, so the request is treated as 'never connected' and UnauthorizedException('Ics Feed not connected.') is thrown (HTTP 401, not 400, because the discrepancy implies a session/state problem).

Source

Thrown at apps/api/v2/src/platform/calendars/services/ics-feed.service.ts:106

      ICS_CALENDAR_TYPE,
      userId
    );

    if (!icsFeedCredentials) {
      throw new BadRequestException("Credentials for Ics Feed calendar not found.");
    }

    if (icsFeedCredentials.invalid) {
      throw new BadRequestException("Invalid Ics Feed credentials.");
    }

    const { connectedCalendars } = await this.calendarsService.getCalendars(userId);
    const icsCalendar = connectedCalendars.find(
      (cal: { integration: { type: string } }) => cal.integration.type === ICS_CALENDAR_TYPE
    );

    if (!icsCalendar) {
      throw new UnauthorizedException("Ics Feed not connected.");
    }
    if (icsCalendar.error?.message) {
      throw new UnauthorizedException(icsCalendar.error?.message);
    }

    return {
      status: SUCCESS_STATUS,
    };
  }
}

View on GitHub (pinned to 176037d0af)

Solutions

  1. Re-run POST /v2/calendars/ics/save to re-create both the credential and the calendar linkage in one transactional step.
  2. If the issue persists, force-bust the connected-calendars cache for that userId (the save path deletes it; a manual cache flush rules out stale reads).
  3. Check that the user calling /check is the same user (and same team context) that owns the linked calendar.
Defensive patterns

Strategy: validation

Validate before calling

const { connectedCalendars } = await calendarsService.getCalendars(userId);
const linked = connectedCalendars.some(c => c.integration.type === ICS_CALENDAR_TYPE);
if (!linked) {
  // re-run /save to recreate the calendar linkage
}

Try / catch

try {
  await icsFeedService.check(userId);
} catch (e) {
  if (e instanceof UnauthorizedException && e.message === 'Ics Feed not connected.') {
    await icsFeedService.save(userId, userEmail, urls); // relink
  } else throw e;
}

Prevention

When it happens

Trigger: The credential row exists but the connected-calendar linkage row (selectedCalendars / destinationCalendars) was deleted or never created; a partial save that persisted the credential but failed before linking; the cache is stale and getCalendars returns a pre-add snapshot.

Common situations: A previous save partially failed between upsertUserAppCredential and the calendar-linking step; the connectedCalendars cache still serves a pre-add snapshot (note save() calls calendarsCacheService.deleteConnectedAndDestinationCalendarsCache, so a cache that wasn't cleared is the tell); user is on a different account whose credential exists but isn't linked.

Related errors


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