calcom/cal.diy · error · BadRequestException
Invalid Ics Feed credentials.
Error message
Invalid Ics Feed credentials.
What it means
In IcsFeedService.check, after the credential row is found it is inspected for an `invalid` flag. Cal.com marks a credential invalid when a prior calendar operation failed (e.g. a refresh token revoked upstream, a feed that returned auth errors repeatedly). A truthy `invalid` short-circuits with BadRequestException('Invalid Ics Feed credentials.') instead of attempting the live getCalendars call.
Source
Thrown at apps/api/v2/src/platform/calendars/services/ics-feed.service.ts:97
};
} catch (e) {
this.logger.error("Could not add ICS feeds", e);
throw new BadRequestException("Could not add ICS feeds, try using private ics feed.");
}
}
async check(userId: number): Promise<{ status: typeof SUCCESS_STATUS }> {
const icsFeedCredentials = await this.credentialRepository.findCredentialByTypeAndUserId(
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
- Re-save the ICS feed via POST /v2/calendars/ics/save with a fresh, valid URL; upsert will replace the credential and clear invalid.
- In the webapp, remove the broken ICS integration and re-add it so a brand-new credential row is created.
- If invalid flipped due to an encryption-key rotation, re-encrypt or reset the affected credential rows rather than re-adding them one by one.
Defensive patterns
Strategy: validation
Validate before calling
const cred = await credentialRepository.findCredentialByTypeAndUserId(ICS_CALENDAR_TYPE, userId);
if (cred?.invalid) {
// prompt re-save with a fresh URL rather than calling /check
} Try / catch
try {
await icsFeedService.check(userId);
} catch (e) {
if (e instanceof BadRequestException && e.message === 'Invalid Ics Feed credentials.') {
await icsFeedService.save(userId, userEmail, freshUrls); // re-save
} else throw e;
} Prevention
- Re-save the ICS feed whenever the source calendar is moved or re-secured.
- Do not rotate CALENDSO_ENCRYPTION_KEY without re-encrypting existing credentials.
- Surface 'invalid' state in the UI so users re-add proactively.
When it happens
Trigger: The ICS feed URL changed, was made private, or was deleted on the provider side after the initial save; an earlier operation hit the credential and set its `invalid` column to true; the encryption key was rotated so the stored credential key no longer decrypts correctly and the resulting fetch fails enough times to flip invalid.
Common situations: User revoked/deleted the source calendar in Google/Outlook; CALENDSO_ENCRYPTION_KEY was rotated without re-encrypting existing credentials; long-lived credential whose feed moved behind auth.
Related errors
- Listed cals and URLs mismatch: ${listedCals.length} vs. ${ur
- Could not add ICS feeds, try using private ics feed.
- Credentials for Ics Feed calendar not found.
- Ics Feed not connected.
- ${icsCalendar.error?.message}
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/cd92334c02c6a49b.
Report an issue: GitHub.