calcom/cal.diy · error · NotFoundException

Event type with ID=${eventTypeId} does not exist.

Error message

Event type with ID=${eventTypeId} does not exist.

What it means

Thrown by EventTypesService_2024_04_15.deleteEventType (DELETE /v2/event-types/:eventTypeId) when eventTypesRepository.getEventTypeById returns null — no row exists with that id at all. Note the message uses 'ID=' (uppercase) and 'does not exist', distinct from the lowercase 'id' phrasing used elsewhere — useful for log grep.

Source

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

  async getUserToUpdateEvent(user: UserWithProfile) {
    const profileId = this.usersService.getUserMainProfile(user)?.id || null;
    const selectedCalendars = await this.selectedCalendarsRepository.getUserSelectedCalendars(user.id);
    const eventTypeSelectedCalendars =
      await this.selectedCalendarsRepository.getUserEventTypeSelectedCalendar(user.id);
    return {
      ...user,
      locale: user.locale ?? "en",
      profile: { id: profileId },
      userLevelSelectedCalendars: selectedCalendars,
      allSelectedCalendars: [...eventTypeSelectedCalendars, ...selectedCalendars],
    };
  }

  async deleteEventType(eventTypeId: number, userId: number) {
    const existingEventType = await this.eventTypesRepository.getEventTypeById(eventTypeId);
    if (!existingEventType) {
      throw new NotFoundException(`Event type with ID=${eventTypeId} does not exist.`);
    }

    this.checkUserOwnsEventType(userId, existingEventType);

    return this.eventTypesRepository.deleteEventType(eventTypeId);
  }

  checkUserOwnsEventType(userId: number, eventType: Pick<EventType, "id" | "userId">) {
    if (userId !== eventType.userId) {
      throw new ForbiddenException(`User with ID=${userId} does not own event type with ID=${eventType.id}`);
    }
  }
}

View on GitHub (pinned to 176037d0af)

Solutions

  1. Make DELETE idempotent on the client: treat 404 as success.
  2. Refresh the event type list after a delete so the UI cannot target a gone id.
  3. Confirm the id came from the same environment's GET response.
  4. If you need create+delete semantics, store the returned id and delete by that exact value.

Example fix

// before
await api.delete(`/v2/event-types/${id}`);
// after
try { await api.delete(`/v2/event-types/${id}`); }
catch (e) { if (e.response?.status !== 404) throw e; /* already gone */ }
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm existence before DELETE (optional — idempotent catch is usually enough)
try {
  await api.get(`/v2/event-types/${id}`);
} catch (e) {
  if (e.response?.status === 404) return; // already gone
  throw e;
}

Type guard

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

Try / catch

try {
  await api.delete(`/v2/event-types/${id}`);
} catch (e) {
  if (e.response?.status === 404) return; // idempotent success
  throw e;
}

Prevention

When it happens

Trigger: DELETE /v2/event-types/999 where the id does not exist; the event type was already deleted; the id is valid but belongs to a soft-deleted row excluded by the repository filter.

Common situations: Double-delete (second DELETE after success); id from a different deployment; the row was purged by a GDPR/retention job; frontend caching a deleted id.

Related errors


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