{"record":{"id":"52c0a6a60d672cf2","repo":"calcom/cal.diy","slug":"failed-to-update-meeting","errorCode":null,"errorMessage":"Failed to update meeting","messagePattern":"Failed to update meeting","errorType":"http","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"apps/api/v2/src/modules/cal-unified-calendars/services/google-calendar.service.ts","lineNumber":95,"sourceCode":"    const ownerUserEmail = bookingReference?.booking?.user?.email;\n\n    const calendar = await this.getAuthorizedCalendarInstance(\n      ownerUserEmail,\n      bookingReference.credential?.key,\n      bookingReference.delegationCredential\n    );\n\n    const updatePayload = new GoogleCalendarEventInputPipe().transform(updateData);\n\n    try {\n      const event = await calendar.events.patch({\n        calendarId: bookingReference?.externalCalendarId ?? \"primary\",\n        eventId: bookingReference?.uid,\n        requestBody: updatePayload,\n      });\n\n      if (!event.data) {\n        throw new NotFoundException(\"Failed to update meeting\");\n      }\n      return event.data as GoogleCalendarEventResponse;\n    } catch (error) {\n      throw new NotFoundException(\"Failed to update meeting details\");\n    }\n  }\n\n  /**\n   * Gets an authorized Google Calendar instance\n   * Tries delegation credentials first, falls back to direct OAuth\n   */\n  private async getAuthorizedCalendarInstance(\n    userEmail?: string,\n    oAuthCredentials?: Prisma.JsonValue | undefined,\n    delegationCredential?: { id: string } | null\n  ): Promise<calendar_v3.Calendar> {\n    if (userEmail && delegationCredential?.id) {\n      const delegatedCalendar = await this.getDelegatedCalendarInstance(delegationCredential, userEmail);","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/calcom/cal.diy/blob/176037d0afbe572f870a3c702985e7cd83fe6c0c/apps/api/v2/src/modules/cal-unified-calendars/services/google-calendar.service.ts#L77-L113","documentation":"GoogleCalendarService.updateEventDetails throws NotFoundException('Failed to update meeting') when calendar.events.patch resolves but returns no event.data. The PATCH succeeded at the transport level but yielded an empty body, treated by the service as a failed update.","triggerScenarios":"A patch against an event id that Google silently does not return (event deleted between the get and patch, or patched against a calendar where the event no longer exists).","commonSituations":"Race: the event was deleted in Google between the booking-reference lookup and the patch; calendar recreated; partial Google outage returning empty bodies.","solutions":["Re-fetch the event to confirm it still exists before patching (optimistic-concurrency).","Retry once; if it persists, surface to the user that the meeting is no longer available.","Verify externalCalendarId/uid on the reference are still valid against the live calendar."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Re-check existence right before patching to avoid the empty-response branch\nconst stillExists = await calendar.events.get({ calendarId, eventId }).then(r => !!r.data).catch(() => false);\nif (!stillExists) throw new Error('Meeting vanished before update; aborting');","typeGuard":null,"tryCatchPattern":"try {\n  return await api.v2.calUnified.updateEvent(eventUid, patch);\n} catch (err) {\n  if (err?.statusCode === 404 && /Failed to update meeting$/i.test(err?.message)) {\n    // one retry after re-verifying the event exists\n  }\n  throw err;\n}","preventionTips":["Re-fetch the event immediately before patching to reduce the deletion race window.","Keep externalCalendarId and uid on the reference in sync with the live calendar.","Treat persistent empty responses as 'event gone' rather than retrying indefinitely."],"tags":["calendar","google-calendar","update","api-v2"],"backgroundTag":null,"analyzedSha":"176037d0afbe572f870a3c702985e7cd83fe6c0c","analyzedAt":"2026-08-12T19:12:41.464Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}