{"record":{"id":"64c81acaed578818","repo":"calcom/cal.diy","slug":"googlecalendar-error-message-64c81a","errorCode":null,"errorMessage":"${googleCalendar.error?.message}","messagePattern":"\\$\\{googleCalendar\\.error\\?\\.message\\}","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"apps/api/v2/src/platform/gcal/gcal.controller.ts","lineNumber":114,"sourceCode":"    );\n\n    if (!gcalCredentials) {\n      throw new BadRequestException(\"Credentials for google_calendar not found.\");\n    }\n\n    if (gcalCredentials.invalid) {\n      throw new BadRequestException(\"Invalid google OAuth credentials.\");\n    }\n\n    const { connectedCalendars } = await this.calendarsService.getCalendars(userId);\n    const googleCalendar = connectedCalendars.find(\n      (cal: { integration: { type: string } }) => cal.integration.type === GOOGLE_CALENDAR_TYPE\n    );\n    if (!googleCalendar) {\n      throw new UnauthorizedException(\"Google Calendar not connected.\");\n    }\n    if (googleCalendar.error?.message) {\n      throw new UnauthorizedException(googleCalendar.error?.message);\n    }\n\n    return { status: SUCCESS_STATUS };\n  }\n}\n","sourceCodeStart":96,"sourceCodeEnd":120,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/platform/gcal/gcal.controller.ts#L96-L120","documentation":"Thrown by the GET /v2/gcal/check endpoint when a Google Calendar credential exists but the calendar provider returns an error during the live connectivity check. The calendars service populates connectedCalendars[].error.message when Google's API rejects the token (expired, revoked, or quota hit). The controller re-throws that provider message as an HTTP 401 Unauthorized so the client knows re-authentication is required.","triggerScenarios":"Calling GET /v2/gcal/check after the user revoked Google Calendar access from their Google account security page; calling it with an OAuth refresh token that expired after extended inactivity; calling it during a Google API outage or after exceeding the Google Calendar API daily quota.","commonSituations":"User disconnects the calendar from their Google account but the Cal.com credential row still exists; OAuth client secrets were rotated in Google Cloud Console without re-issuing user tokens; bulk calendar sync exhausts API quota; token invalidated by a Google password change on the user's account.","solutions":["Re-authenticate by redirecting the user through GET /v2/gcal/oauth/auth-url to obtain a fresh authorization code and exchange it for new tokens.","Inspect the credential's `invalid` flag in the database — if true, the token is permanently revoked and only re-authorization will fix it.","Read the raw error.message value from the response to distinguish transient issues (rate limit, 503) from permanent ones (invalid_grant, revoked).","Check the Google Cloud Console IAM quotas and enabled API status for the Calendar API to rule out quota exhaustion."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Before calling /v2/gcal/check, verify credential exists\nconst credentials = await api.get('/v2/gcal/check');\n// Pre-flight: check if user has google_calendar credential type\n// This doesn't prevent provider errors but catches missing credentials early","typeGuard":null,"tryCatchPattern":"try {\n  await api.get('/v2/gcal/check');\n} catch (error) {\n  if (error.response?.status === 401) {\n    // Token is expired or revoked — re-initiate OAuth flow\n    const { data } = await api.get('/v2/gcal/oauth/auth-url');\n    window.location.href = data.data.authUrl;\n  } else {\n    throw error;\n  }\n}","preventionTips":["Implement automatic OAuth re-authorization when /v2/gcal/check returns 401.","Periodically call /v2/gcal/check during off-peak hours to detect stale tokens early.","Log the underlying error.message to distinguish transient from permanent failures.","Set up monitoring on Google Calendar API quotas to prevent quota-exhaustion errors."],"tags":["google-calendar","oauth","calendar","integration","auth","nestjs"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}