calcom/cal.diy · error · UnauthorizedException
Apple calendar not connected.
Error message
Apple calendar not connected.
What it means
Thrown by AppleCalendarService.checkIfCalendarConnected (apple-calendar.service.ts:51) as UnauthorizedException (HTTP 401) when the credential row exists and is valid, but calendarsService.getCalendars(userId) returned a connectedCalendars array containing no entry whose integration.type === APPLE_CALENDAR_TYPE. The credential is stored but no Apple calendar is actually surfaced/linked by the integration layer.
Source
Thrown at apps/api/v2/src/platform/calendars/services/apple-calendar.service.ts:51
const appleCalendarCredentials = await this.credentialRepository.findCredentialByTypeAndUserId(
APPLE_CALENDAR_TYPE,
userId
);
if (!appleCalendarCredentials) {
throw new BadRequestException("Credentials for apple calendar not found.");
}
if (appleCalendarCredentials.invalid) {
throw new BadRequestException("Invalid apple calendar credentials.");
}
const { connectedCalendars } = await this.calendarsService.getCalendars(userId);
const appleCalendar = connectedCalendars.find(
(cal: { integration: { type: string } }) => cal.integration.type === APPLE_CALENDAR_TYPE
);
if (!appleCalendar) {
throw new UnauthorizedException("Apple calendar not connected.");
}
if (appleCalendar.error?.message) {
throw new UnauthorizedException(appleCalendar.error?.message);
}
return {
status: SUCCESS_STATUS,
};
}
async saveCalendarCredentials(userId: number, userEmail: string, username: string, password: string) {
if (!username || !password || username.length <= 1 || password.length <= 1) {
throw new BadRequestException(`Username or password cannot be empty`);
}
const existingAppleCalendarCredentials = await this.credentialRepository.getAllUserCredentialsByTypeAndId(
APPLE_CALENDAR_TYPE,
userIdView on GitHub (pinned to 176037d0af)
Solutions
- Invalidate the connected-calendars cache for the user (calendarsCacheService.deleteConnectedAndDestinationCalendarsCache) and retry check.
- Confirm a SelectedCalendars row exists for the apple calendar externalId + credentialId.
- Re-run the save flow, which calls dav.listCalendars() and upserts the credential, forcing the integration to re-link.
Example fix
// before: check immediately after save returns 401 due to stale cache
await api.post('/v2/calendars/apple_calendar/save', { ... });
await api.get('/v2/calendars/apple_calendar/check'); // 401 'Apple calendar not connected.'
// after: clear cache (server-side) or wait for invalidation, then check
calendarsCacheService.deleteConnectedAndDestinationCalendarsCache(userId);
await api.get('/v2/calendars/apple_calendar/check'); // 200 Defensive patterns
Strategy: validation
Validate before calling
// Confirm the apple calendar appears in the (cache-busted) list before checking
await api.post('/v2/calendars/apple_calendar/save', { username, password });
// server should invalidate cache; if not, force a refresh path that bypasses cache
const { data } = await api.get('/v2/calendars', { params: { ensureDefaultSelectedCalendars: true } });
const linked = data.connectedCalendars.some(c => c.integration?.type === 'apple_calendar');
if (!linked) throw new Error('Apple calendar did not link — see save logs'); Type guard
function hasConnectedApple(list) {
return Array.isArray(list) && list.some(
(c) => c?.integration?.type === 'apple_calendar'
);
} Try / catch
try {
await api.get('/v2/calendars/apple_calendar/check');
} catch (e) {
if (e.response?.status === 401 && /not connected/i.test(e.response?.data?.message)) {
// likely stale cache or incomplete link — re-save then retry once
await api.post('/v2/calendars/apple_calendar/save', { username, password });
return api.get('/v2/calendars/apple_calendar/check');
}
throw e;
} Prevention
- Invalidate CalendarsCacheService after every save (deleteConnectedAndDestinationCalendarsCache).
- Confirm a SelectedCalendars row is created during save before reporting success.
- Avoid polling 'check' in a tight loop immediately after save — add a short delay or cache-bust.
When it happens
Trigger: Credential saved but the link/selectedCalendars step never completed; CalendarsCacheService returns a stale cached list missing the apple entry (cache not invalidated after save); the integration returned calendars but none matched the type filter.
Common situations: Race between an in-flight save and a check; cache key stale because save didn't call deleteConnectedAndDestinationCalendarsCache; selectedCalendars row missing for the apple calendar.
Related errors
- Google Calendar not connected.
- ${appleCalendar.error?.message}
- CustomThrottlerGuard - Invalid API Key
- ApiKeysService - This endpoint can only be accessed using an
- ApiKeysService - No API key provided
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/c4ce1e51bc285639.
Report an issue: GitHub.