calcom/cal.diy · error · UnauthorizedException
Google Calendar is not connected for this user
Error message
Google Calendar is not connected for this user
What it means
Thrown by getCalendarClientForUser when findCredentialWithDelegationByTypeAndUserId returns null — no AppCredential row of type google_calendar exists for the given userId. Returns HTTP 401 via UnauthorizedException. This is the user-scoped entry point used by listEventsForUser/createEventForUser/deleteEventForUser.
Source
Thrown at apps/api/v2/src/modules/cal-unified-calendars/services/google-calendar.service.ts:177
await authClient.authorize();
return new calendar_v3.Calendar({ auth: authClient });
} catch (error) {
return null;
}
}
/**
* Gets an authorized Google Calendar instance for the given user (for user-scoped list/create/delete).
* Tries delegated auth first (if available), then falls back to direct OAuth.
*/
async getCalendarClientForUser(userId: number): Promise<calendar_v3.Calendar> {
const credential = await this.credentialsRepository.findCredentialWithDelegationByTypeAndUserId(
GOOGLE_CALENDAR_TYPE,
userId
);
if (!credential) {
throw new UnauthorizedException("Google Calendar is not connected for this user");
}
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) {View on GitHub (pinned to 176037d0af)
Solutions
- Have the user complete the Google Calendar OAuth connect flow to create a google_calendar credential row.
- Verify the userId passed matches the credential owner (SELECT "userId", type FROM "AppCredential" WHERE type='google_calendar' AND "userId"=?).
- If the user should use a team/org-scoped calendar, call the connection-scoped endpoints with the correct credentialId instead.
- Surface a clear UI prompt to connect Google Calendar before allowing event operations.
Example fix
// before
const events = await googleCalendarService.listEventsForUser(userId, calId, t0, t1);
// after: validate connection state first
const cred = await credentialsRepository.findCredentialWithDelegationByTypeAndUserId(GOOGLE_CALENDAR_TYPE, userId);
if (!cred) {
return { status: 'requires_connection', url: '/apps/google-calendar' };
} Defensive patterns
Strategy: validation
Validate before calling
async function ensureGoogleCalendarConnected(userId: number): Promise<void> {
const cred = await credentialsRepository.findCredentialWithDelegationByTypeAndUserId(GOOGLE_CALENDAR_TYPE, userId);
if (!cred) {
throw new Error(`User ${userId} has no google_calendar credential. Direct them to connect.`);
}
}
await ensureGoogleCalendarConnected(userId); Type guard
interface HasGoogleCalendar {
type: string;
userId: number;
}
function isGoogleCalendarCredential<T extends { type: string }>(c: T | null): c is T & { type: 'google_calendar' } {
return c !== null && c.type === 'google_calendar';
} Try / catch
try {
await googleCalendarService.listEventsForUser(userId, calId, t0, t1);
} catch (e) {
if (e instanceof UnauthorizedException && /not connected/.test(e.message)) {
return res.status(422).json({ code: 'calendar_not_connected', connectUrl: '/apps/google-calendar' });
}
throw e;
} Prevention
- Surface a 'Connect Google Calendar' step in onboarding before exposing event endpoints.
- Cache the connection state in the session so the UI knows it before each call.
- Return a structured error code (calendar_not_connected) instead of relying on message matching.
When it happens
Trigger: Calling any user-scoped unified-calendar endpoint (POST /v2/calendars/{calendar}/events, GET .../events, DELETE) for a user who never connected Google Calendar, or whose only google_calendar credential belongs to a different userId (team/org credentials are not returned by this user-scoped query).
Common situations: User signed up but skipped calendar onboarding; the google_calendar credential was deleted via the disconnect flow; testing with a userId from a different environment; user connected only Office 365 or Apple.
Related errors
- No valid credentials available for Google Calendar
- Google Calendar credentials are invalid. Please reconnect.
- Calendar credentials are invalid. Please reconnect.
- Credentials for google_calendar not found.
- Calendar connection not found
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/889094bf5e0e5891.
Report an issue: GitHub.