calcom/cal.diy · error · NotFoundException
Calendar connection not found
Error message
Calendar connection not found
What it means
Thrown by getCalendarClientByCredentialId when findCredentialByIdAndUserId(credentialId, userId) returns null — the supplied credentialId does not exist OR does not belong to the supplied userId. Returns HTTP 404 via NotFoundException. This is the connection-scoped entry point (listConnectionEvents, createConnectionEvent, etc.).
Source
Thrown at apps/api/v2/src/modules/cal-unified-calendars/services/google-calendar.service.ts:196
}
if (credential.invalid) {
throw new UnauthorizedException("Google Calendar credentials are invalid. Please reconnect.");
}
return this.getAuthorizedCalendarInstance(
credential.user?.email ?? undefined,
credential.key,
credential.delegationCredentialId ? { id: credential.delegationCredentialId } : null
);
}
/**
* Gets an authorized Google Calendar instance for a specific credential (connection).
* Tries delegated auth first (if available), then falls back to direct OAuth.
*/
async getCalendarClientByCredentialId(userId: number, credentialId: number): Promise<calendar_v3.Calendar> {
const credential = await this.credentialsRepository.findCredentialByIdAndUserId(credentialId, userId);
if (!credential) {
throw new NotFoundException("Calendar connection not found");
}
if (credential.type !== GOOGLE_CALENDAR_TYPE) {
throw new BadRequestException(
"Event operations for this connection are currently only available for Google Calendar"
);
}
if (credential.invalid) {
throw new UnauthorizedException("Calendar credentials are invalid. Please reconnect.");
}
return this.getAuthorizedCalendarInstance(
credential.user?.email ?? undefined,
credential.key,
credential.delegationCredentialId ? { id: credential.delegationCredentialId } : null
);
}
// ─── Shared private helpers (DRY calendar CRUD) ──────────────────────
View on GitHub (pinned to 176037d0af)
Solutions
- Refresh the connections list via GET /v2/calendars/connections and use a current connectionId.
- Confirm the credentialId belongs to the calling user: SELECT id, "userId" FROM "AppCredential" WHERE id=? AND "userId"=?.
- If the credential was deleted, instruct the user to reconnect and obtain a new connectionId.
- Validate that connectionId is a positive integer before the request.
Example fix
// before
const event = await googleCalendarService.getEventByConnectionId(userId, Number(connectionId), calId, evId);
// after
const connectionIdNum = Number(connectionId);
if (!Number.isInteger(connectionIdNum) || connectionIdNum <= 0) {
throw new BadRequestException('connectionId must be a positive integer.');
}
const cred = await credentialsRepository.findCredentialByIdAndUserId(connectionIdNum, userId);
if (!cred) {
throw new NotFoundException(`No calendar connection ${connectionIdNum} for user ${userId}.`);
} Defensive patterns
Strategy: validation
Validate before calling
function parseConnectionId(raw: string): number {
const n = Number(raw);
if (!Number.isInteger(n) || n <= 0) {
throw new BadRequestException('connectionId must be a positive integer.');
}
return n;
}
async function connectionBelongsToUser(connectionId: number, userId: number): Promise<boolean> {
const cred = await credentialsRepository.findCredentialByIdAndUserId(connectionId, userId);
return Boolean(cred);
}
const id = parseConnectionId(req.params.connectionId);
if (!(await connectionBelongsToUser(id, userId))) {
throw new NotFoundException('Calendar connection not found.');
} Type guard
function isPositiveInt(n: unknown): n is number {
return typeof n === 'number' && Number.isInteger(n) && n > 0;
} Try / catch
try {
return await googleCalendarService.getEventByConnectionId(userId, credentialId, calId, evId);
} catch (e) {
if (e instanceof NotFoundException && /not found/i.test(e.message)) {
return res.status(404).json({ code: 'connection_not_found', connectionId });
}
throw e;
} Prevention
- Always type-coerce and range-check connectionId at the controller boundary.
- Refresh the client connection list after any disconnect/reconnect to avoid stale ids.
- Never accept connectionId from an untrusted source without an ownership check.
When it happens
Trigger: Calling any /v2/calendars/connections/{connectionId}/... endpoint with a connectionId that is stale, deleted, belongs to another user, or was transposed (typo). Also triggered when a team/org credential is referenced by userId when the query filters by owner.
Common situations: Frontend cached an old connection list after the user disconnected; cross-tenant access attempt; integer parsing of connectionId produced a wrong value; the connection was deleted in another session.
Related errors
- Calendar credentials are invalid. Please reconnect.
- No valid credentials available for Google Calendar
- Google Calendar is not connected for this user
- Google Calendar credentials are invalid. Please reconnect.
- Event not found
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/3f206ca13a2d550b.
Report an issue: GitHub.