calcom/cal.diy · error · BadRequestException
Invalid apple calendar credentials.
Error message
Invalid apple calendar credentials.
What it means
Thrown by AppleCalendarService.checkIfCalendarConnected (apple-calendar.service.ts:43) as BadRequestException (HTTP 400) when the Apple Calendar credential row exists but its 'invalid' column is true. The flag is set by upstream code when a prior DAV authentication or listCalendars call failed, marking the stored username/password as no longer working.
Source
Thrown at apps/api/v2/src/platform/calendars/services/apple-calendar.service.ts:43
return await this.saveCalendarCredentials(userId, userEmail, username, password);
}
async check(userId: number): Promise<{ status: typeof SUCCESS_STATUS }> {
return await this.checkIfCalendarConnected(userId);
}
async checkIfCalendarConnected(userId: number): Promise<{ status: typeof SUCCESS_STATUS }> {
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,
};
}
View on GitHub (pinned to 176037d0af)
Solutions
- Re-save the credential via the 'save' endpoint — saveCalendarCredentials upserts and overwrites the invalid row (see lines 97-108 for the update path).
- Have the user generate a fresh app-specific password at appleid.apple.com and submit it via save.
- Confirm the 'invalid' column is reset to false after a successful save before retrying check.
Example fix
// before: re-checking an invalid credential
await api.get('/v2/calendars/apple_calendar/check'); // 400 'Invalid apple calendar credentials.'
// after: overwrite with fresh app-specific password
await api.post('/v2/calendars/apple_calendar/save', {
username: userAppleId,
password: newlyGeneratedAppSpecificPassword,
}); Defensive patterns
Strategy: validation
Validate before calling
// Check the invalid flag via the calendars list before calling check
const { data } = await api.get('/v2/calendars');
const apple = data.connectedCalendars.find(c => c.integration?.type === 'apple_calendar');
if (apple?.error || apple === undefined) {
// credential missing or invalid — prompt re-save
await promptAppleReSave();
} Type guard
function isCredentialValid(cred) {
return !!cred && cred.invalid === false;
} Try / catch
try {
await api.get('/v2/calendars/apple_calendar/check');
} catch (e) {
if (e.response?.status === 400 && /invalid/i.test(e.response?.data?.message)) {
await reSaveAppleCredentials(); // overwrite the invalid row
return;
}
throw e;
} Prevention
- When a listCalendars/DAV call fails, mark invalid and prompt the user to re-save rather than silently retrying.
- App-specific passwords should be regenerated at appleid.apple.com when rotated.
- After a successful save, assert the invalid flag is false before proceeding.
When it happens
Trigger: Calling 'check' after the credential was flagged invalid by a previous failed listCalendars/refresh; user rotated their Apple ID password or revoked the app-specific password; the credential row's invalid flag was set by an admin/migration.
Common situations: User changed their Apple ID password; app-specific password revoked at appleid.apple.com; long-dormant credential that failed a background refresh.
Related errors
- Credentials for apple calendar not found.
- No valid credentials available for Google Calendar
- Google Calendar credentials are invalid. Please reconnect.
- ${appleCalendar.error?.message}
- Username or password cannot be empty
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/31b38eae4935ece5.
Report an issue: GitHub.