{"record":{"id":"95cf2cedc845383a","repo":"calcom/cal.diy","slug":"google-meet-is-already-connected-for-this-user","errorCode":null,"errorMessage":"Google Meet is already connected for this user.","messagePattern":"Google Meet is already connected for this user\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"info","filePath":"apps/api/v2/src/modules/conferencing/services/google-meet.service.ts","lineNumber":22,"sourceCode":"import { Injectable } from \"@nestjs/common\";\n\nimport { GOOGLE_CALENDAR_TYPE, GOOGLE_MEET_TYPE } from \"@calcom/platform-constants\";\n\n@Injectable()\nexport class GoogleMeetService {\n  private logger = new Logger(\"GoogleMeetService\");\n\n  constructor(\n    private readonly conferencingRepository: ConferencingRepository,\n    private readonly credentialsRepository: CredentialsRepository\n  ) {}\n\n  async connectGoogleMeetToUser(userId: number) {\n    await this.validateGoogleCalendarConnection(userId, \"user\");\n\n    const googleMeetExists = await this.conferencingRepository.findGoogleMeet(userId);\n    if (googleMeetExists) {\n      throw new BadRequestException(\"Google Meet is already connected for this user.\");\n    }\n\n    return this.credentialsRepository.upsertUserAppCredential(GOOGLE_MEET_TYPE, {}, userId);\n  }\n\n  async connectGoogleMeetToTeam(teamId: number) {\n    await this.validateGoogleCalendarConnection(teamId, \"team\");\n\n    const googleMeetExists = await this.credentialsRepository.findCredentialByTypeAndTeamId(\n      GOOGLE_MEET_TYPE,\n      teamId\n    );\n    if (googleMeetExists) {\n      throw new BadRequestException(\"Google Meet is already connected for this team.\");\n    }\n\n    return this.credentialsRepository.upsertTeamAppCredential(GOOGLE_MEET_TYPE, {}, teamId);\n  }","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/conferencing/services/google-meet.service.ts#L4-L40","documentation":"Thrown by GoogleMeetService.connectGoogleMeetToUser when conferencingRepository.findGoogleMeet(userId) returns an existing credential — the user already has a google_meet credential row. Returns HTTP 400 via BadRequestException. Connecting again would create a duplicate; the existing credential is reused. Reached via POST /v2/conferencing/google_meet/connect → connectUserNonOauthApp.","triggerScenarios":"User clicks 'Connect Google Meet' a second time; the frontend did not refresh its connected-apps state after the first connect; a retry fired because the first response was slow.","commonSituations":"UI button stays enabled after connect; double-submit (no debounce); race between two connect clicks; the connect succeeded but the response was lost and the client retried.","solutions":["Before calling connect, check GET /v2/conferencing — if google_meet is listed, skip the connect call.","Disable the connect button immediately on click (debounce) to prevent double-submit.","Treat this 400 as success-equivalent in the client (idempotent connect) since the end state — Google Meet connected — is achieved.","If you want true idempotency, switch the service to upsert instead of throw on duplicate."],"exampleFix":"// before\nawait api.connectConferencing('google_meet');\n\n// after\nconst installed = await api.listConferencingApps();\nif (!installed.data.some(a => a.slug === 'google_meet')) {\n  await api.connectConferencing('google_meet');\n} else {\n  showToast('Google Meet is already connected.');\n}","handlingStrategy":"validation","validationCode":"async function googleMeetAlreadyConnected(conferencingRepository: ConferencingRepository, userId: number): Promise<boolean> {\n  return Boolean(await conferencingRepository.findGoogleMeet(userId));\n}\n\nif (await googleMeetAlreadyConnected(conferencingRepository, userId)) {\n  return { status: 'already_connected', app: 'google_meet' };\n}","typeGuard":"function isGoogleMeetCredential<T extends { type: string }>(c: T | null): c is T & { type: 'google_meet' } {\n  return c !== null && c.type === 'google_meet';\n}","tryCatchPattern":"try {\n  await googleMeetService.connectGoogleMeetToUser(userId);\n} catch (e) {\n  if (e instanceof BadRequestException && /already connected/i.test(e.message)) {\n    // idempotent — treat as success\n    return { status: 'already_connected' };\n  }\n  throw e;\n}","preventionTips":["Disable the connect button client-side immediately on click.","Check GET /v2/conferencing for google_meet before offering the connect action.","Treat the 'already connected' 400 as success-equivalent to make connect idempotent.","Refresh the installed-apps list after a successful connect to keep UI state accurate."],"tags":["conferencing","google-meet","validation","nestjs","duplicate","connect"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}