calcom/cal.diy · error · BadRequestException

User already has an event type with this slug.

Error message

User already has an event type with this slug.

What it means

Thrown by EventTypesService_2024_04_15.checkCanCreateEventType (POST /v2/event-types) when eventTypesRepository.getUserEventTypeBySlug returns a row — meaning the authenticated user already owns an event type with the requested slug. Slugs are unique per user, so the create is rejected before any write.

Source

Thrown at apps/api/v2/src/platform/event-types/event-types_2024_04_15/services/event-types.service.ts:56

  ): Promise<EventTypeOutput> {
    await this.checkCanCreateEventType(user.id, body);
    const eventTypeUser = await this.getUserToCreateEvent(user);
    const { eventType } = await createEventType({
      input: body,
      ctx: {
        user: eventTypeUser,
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        prisma: this.dbWrite.prisma,
      },
    });
    return eventType as EventTypeOutput;
  }

  async checkCanCreateEventType(userId: number, body: CreateEventTypeInput_2024_04_15) {
    const existsWithSlug = await this.eventTypesRepository.getUserEventTypeBySlug(userId, body.slug);
    if (existsWithSlug) {
      throw new BadRequestException("User already has an event type with this slug.");
    }
  }

  async getUserToCreateEvent(user: UserWithProfile) {
    const organizationId = this.usersService.getUserMainOrgId(user);
    const isOrgAdmin = organizationId
      ? await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId)
      : false;
    const profileId = this.usersService.getUserMainProfile(user)?.id || null;
    return {
      id: user.id,
      role: user.role,
      organizationId: user.organizationId,
      organization: { isOrgAdmin },
      profile: { id: profileId },
      metadata: user.metadata,
      email: user.email,
    };

View on GitHub (pinned to 176037d0af)

Solutions

  1. GET /v2/event-types and check the slug is unused before POSTing.
  2. Generate a unique slug by appending a suffix (e.g. '-1', '-2') when the preferred slug is taken.
  3. If the previous create may have succeeded, treat this 400 as a hint to refresh and switch to PATCH on the existing id.
  4. Make slug generation idempotent by deriving it from a stable external id rather than the title.

Example fix

// before
await api.post('/v2/event-types', { slug: 'thirty-min', length: 30, ... });
// after
const existing = (await api.get('/v2/event-types')).data.find(e => e.slug === 'thirty-min');
if (existing) throw new Error('slug taken');
await api.post('/v2/event-types', { slug: 'thirty-min', length: 30, ... });
Defensive patterns

Strategy: validation

Validate before calling

// Check slug uniqueness before create
const mine = (await api.get('/v2/event-types')).data ?? [];
if (mine.some((e) => e.slug === body.slug)) {
  throw new Error(`slug ${body.slug} already used by this user`);
}

Type guard

function isUniqueSlug(list: unknown, slug: string): boolean {
  return Array.isArray(list) && !list.some((e) => typeof e === 'object' && e !== null && (e as any).slug === slug);
}

Try / catch

try {
  await api.post('/v2/event-types', body);
} catch (e) {
  if (e.response?.status === 400 && e.response?.data?.message?.includes('slug')) {
    // append a suffix and retry, or switch to PATCH on the existing id
  } else throw e;
}

Prevention

When it happens

Trigger: POST /v2/event-types with a `slug` that duplicates an existing event type's slug for the same user; re-issuing a create after a partial success; slug collision after renaming another event type to the same slug.

Common situations: Retrying a create that actually succeeded (network blip) but with the same slug; generating slugs deterministically from a title that already exists; importing event types without slug deduplication; frontend not refreshing the list after a create.

Related errors


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