calcom/cal.diy · error · BadRequestException

Credentials for Ics Feed calendar not found.

Error message

Credentials for Ics Feed calendar not found.

What it means

Thrown by IcsFeedService.check, the connectivity-check handler. It calls credentialRepository.findCredentialByTypeAndUserId(ICS_CALENDAR_TYPE, userId); if no credential row of type 'ics_calendar' exists for that user, BadRequestException is raised because there is nothing to validate. This is a precondition gate before the more expensive getCalendars call.

Source

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

          teamId: credential.teamId,
          appId: credential.appId,
          invalid: credential.invalid,
        },
      };
    } 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);
    }

View on GitHub (pinned to 176037d0af)

Solutions

  1. Run POST /v2/calendars/ics/save first to create the ICS credential, then call /check.
  2. Confirm the userId sent to /check is the same numeric user id returned by the save call.
  3. If the credential was intentionally deleted, stop polling /check or treat a 400 here as 'not configured' rather than an error.

Example fix

// before
const status = await api.get(`/v2/calendars/ics/check?userId=${userId}`);

// after
if (!icsCredentialExists) {
  await api.post('/v2/calendars/ics/save', { userId, userEmail, urls });
}
const status = await api.get(`/v2/calendars/ics/check?userId=${userId}`);
Defensive patterns

Strategy: validation

Validate before calling

const cred = await credentialRepository.findCredentialByTypeAndUserId(ICS_CALENDAR_TYPE, userId);
if (!cred) {
  return { status: 'not_configured' }; // prompt user to save an ICS feed
}

Try / catch

try {
  await icsFeedService.check(userId);
} catch (e) {
  if (e instanceof BadRequestException && e.message.includes('not found')) {
    // treat as 'not configured' and trigger the save flow
  } else throw e;
}

Prevention

When it happens

Trigger: Calling GET /v2/calendars/ics/check (or check) for a user who has never saved an ICS feed via /save; passing a userId that belongs to a different user or environment; the credential was deleted between save and check; the type string passed is not exactly ICS_CALENDAR_TYPE.

Common situations: Frontend calls /check before the user has completed /save; a user removed the ICS integration from the webapp and the client still polls /check; test/dev environment with a different userId than the one that created the credential.

Related errors


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