calcom/cal.diy · error · BadRequestException

Video integration "${ctx.integrationSlug}" is not connected.

Error message

Video integration "${ctx.integrationSlug}" is not connected. Please connect the integration in your settings first.

What it means

Thrown by handleVideoApiIntegration (the default branch covering Zoom, Webex, Whereby, etc.) when bookingVideoService.findVideoCredentialForIntegration returns null. That method scans the booking host's credentials for one matching the integration slug; no match means the host never connected that video app, so there is no credential to create the meeting with.

Source

Thrown at apps/api/v2/src/platform/bookings/2024-08-13/services/booking-location-integration.service.ts:195

      bookingId: ctx.existingBooking.id,
      newReferencesToCreate: [newReference],
    });

    if (videoCallUrl) {
      await this.calendarSyncService.syncCalendarEvent(ctx.existingBooking.id, bookingLocation);
    }

    return this.updateBookingWithVideoLocation(ctx, videoCallUrl, bookingLocation, evt);
  }

  private async handleVideoApiIntegration(ctx: IntegrationHandlerContext): Promise<BookingLocationResponse> {
    const credential = await this.bookingVideoService.findVideoCredentialForIntegration(
      ctx.integrationSlug,
      ctx.booking.user?.credentials || []
    );

    if (!credential) {
      throw new BadRequestException(
        `Video integration "${ctx.integrationSlug}" is not connected. Please connect the integration in your settings first.`
      );
    }

    await this.bookingVideoService.deleteOldVideoMeetingIfNeeded(ctx.existingBooking.id);

    const evt = await this.calendarSyncService.buildCalEventFromBookingData(
      ctx.booking,
      ctx.internalLocation,
      credential.id
    );
    const meetingResult = await createMeeting(credential, evt);

    if (!meetingResult.createdEvent) {
      this.logger.error(
        `Failed to create video meeting with ${ctx.integrationSlug}`,
        JSON.stringify({ success: meetingResult.success, type: meetingResult.type })
      );

View on GitHub (pinned to 176037d0af)

Solutions

  1. Have the booking host connect the integration in Cal.com Settings > Apps (complete the OAuth flow).
  2. If previously connected, reconnect to re-establish the credential after a token revocation.
  3. Confirm the integration slug sent in the request matches a connected app (see apiToInternalintegrationsMapping for valid slugs).
  4. Use an integration the host has actually connected, or fall back to cal-video.
Defensive patterns

Strategy: validation

Validate before calling

// Before PATCHing to a video integration, check the host has a connected credential.
const integrations = await api.get('/v2/connected-apps'); // or equivalent credential check
const connected = integrations.some((i) => i.slug === integrationSlug);
if (!connected) throw new Error(`Integration ${integrationSlug} is not connected by the booking host`);

Type guard

function hasVideoCredential(credentials: { type: string }[] | null | undefined, slug: string): boolean {
  return !!credentials && credentials.some((c) => c.type.includes(slug));
}

Try / catch

try {
  await api.patch(`/v2/bookings/${uid}/location`, { location: { type: 'integration', integration: slug } });
} catch (err) {
  if (err.status === 400 && /is not connected/.test(err.message)) {
    // prompt the host to connect the app, or fall back to cal-video
  }
  throw err;
}

Prevention

When it happens

Trigger: PATCH booking location to any non-special integration slug (zoom, whereby-video, webex-video, whatsapp-video, etc.) when the booking host user has no stored credential of that type.

Common situations: User installed the app on a different Cal.com account; credential deleted when the user disconnected the app; OAuth token fully expired/revoked so the credential row was removed; misspelled integration slug that maps to nothing connected.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/2861a9ab72664cc9. Report an issue: GitHub.