{"record":{"id":"d49c7306657feb94","repo":"calcom/cal.diy","slug":"credentials-for-google-calendar-not-found","errorCode":null,"errorMessage":"Credentials for google_calendar not found.","messagePattern":"Credentials for google_calendar not found\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"apps/api/v2/src/platform/calendars/services/gcal.service.ts","lineNumber":107,"sourceCode":"\n    if (!app) {\n      throw new NotFoundException();\n    }\n\n    const { client_id, client_secret } = this.gcalResponseSchema.parse(app.keys);\n\n    const oAuth2Client = new OAuth2Client(client_id, client_secret, redirectUri);\n    return oAuth2Client;\n  }\n\n  async checkIfCalendarConnected(userId: number): Promise<{ status: typeof SUCCESS_STATUS }> {\n    const gcalCredentials = await this.credentialRepository.findCredentialByTypeAndUserId(\n      \"google_calendar\",\n      userId\n    );\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 };","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/platform/calendars/services/gcal.service.ts#L89-L125","documentation":"Thrown by GoogleCalendarService.checkIfCalendarConnected (gcal.service.ts:107) as BadRequestException (HTTP 400) when findCredentialByTypeAndUserId('google_calendar', userId) returns null — no Google Calendar credential stored for the user. Semantic mismatch like error 360: a 'not found' condition reported as 400. Reached via the google_calendar 'check' endpoint.","triggerScenarios":"Calling check for google_calendar before completing the OAuth connect→save flow; user never authorized Google; credential was disconnected/deleted.","commonSituations":"OAuth callback not yet processed; onboarding polling check before save completes; user revoked and the credential row was removed.","solutions":["Complete the Google OAuth flow first: connect (get authUrl) → user authorizes → save (callback) → then check.","Confirm the credential row exists: SELECT id FROM \"Credential\" WHERE type='google_calendar' AND \"userId\"=<id>.","If invalid=true (error 377), re-run the OAuth flow."],"exampleFix":"// before: checking before OAuth completes\nawait api.get('/v2/calendars/google_calendar/check'); // 400\n\n// after: complete connect → save → check\nconst { data } = await api.post('/v2/calendars/google_calendar/connect', {});\n// user visits data.authUrl, authorizes, returns with ?code=\nawait api.post('/v2/calendars/google_calendar/save', { code, ... });\nawait api.get('/v2/calendars/google_calendar/check'); // 200","handlingStrategy":"validation","validationCode":"// Confirm a google credential exists before calling check\nconst { data } = await api.get('/v2/calendars');\nconst hasGoogle = data.connectedCalendars.some(c => c.integration?.type === 'google_calendar');\nif (!hasGoogle) {\n  // route the user to OAuth connect instead of calling check\n  return redirectToGoogleConnect();\n}","typeGuard":"function hasGoogleCredential(list) {\n  return Array.isArray(list) && list.some(c => c?.integration?.type === 'google_calendar');\n}","tryCatchPattern":"try {\n  await api.get('/v2/calendars/google_calendar/check');\n} catch (e) {\n  if (e.response?.status === 400 && /not found/i.test(e.response?.data?.message)) {\n    // not yet connected — start OAuth rather than retry\n    return startGoogleOAuth();\n  }\n  throw e;\n}","preventionTips":["Complete connect → save before calling check.","Treat 400 'Credentials ... not found' as a connect prompt, not a transient retry.","Clear any client-side 'connected' state on disconnect."],"tags":["google-calendar","credentials","oauth","onboarding","http-400"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}