calcom/cal.diy · error · BadRequestException

checkIsEmailUserAccessible - Email booking field must be req

Error message

checkIsEmailUserAccessible - Email booking field must be required and visible

What it means

Thrown by EventTypesService_2024_06_14.checkHasUserAccessibleEmailBookingField when the email booking field is not both `required` and not `hidden`. The 2024_06_14 create/update flow enforces that the `email` system field remains user-accessible (required and visible) so booking confirmations and attendee notifications can be delivered. It fires on both create (when bookingFields is provided) and update.

Source

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

    return {
      ownerId: eventType.userId ?? 0,
      ...eventType,
    };
  }

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

  checkHasUserAccessibleEmailBookingField(bookingFields: (SystemField | CustomField)[]) {
    const emailField = bookingFields.find((field) => field.type === "email" && field.name === "email");
    const isEmailFieldRequiredAndVisible = emailField?.required && !emailField?.hidden;
    if (!isEmailFieldRequiredAndVisible) {
      throw new BadRequestException(
        "checkIsEmailUserAccessible - Email booking field must be required and visible"
      );
    }
  }

  async getEventTypeByUsernameAndSlug(params: {
    username: string;
    eventTypeSlug: string;
    orgSlug?: string;
    orgId?: number;
    authUser?: AuthOptionalUser;
  }) {
    const user = await this.usersRepository.findByUsername(params.username, params.orgSlug, params.orgId);
    if (!user) {
      return null;
    }

    const eventType = await this.eventTypesRepository.getUserEventTypeBySlug(user.id, params.eventTypeSlug);

View on GitHub (pinned to 176037d0af)

Solutions

  1. Ensure the bookingFields array includes an entry with type 'email', name 'email', required true, and hidden false (or omitted/undefined).
  2. When PATCHing only a subset of bookingFields, re-include the email field with required:true and hidden:false.
  3. Validate your payload against the SystemField schema before sending — use the platform-types definition.
  4. If you genuinely need a no-email event type, use a different flow (e.g. managed events) that does not route through this check.

Example fix

// before
await api.patch(`/v2/event-types/${id}`, {
  bookingFields: [{ type: 'email', name: 'email', required: false, hidden: true }]
}, { headers: { 'cal-api-version': '2024-06-14' } });
// after
await api.patch(`/v2/event-types/${id}`, {
  bookingFields: [{ type: 'email', name: 'email', required: true, hidden: false }]
}, { headers: { 'cal-api-version': '2024-06-14' } });
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure the email booking field is required and visible before create/update
function ensureEmailFieldAccessible(bookingFields: any[]) {
  const email = bookingFields.find((f) => f.type === 'email' && f.name === 'email');
  if (!email || !email.required || email.hidden) {
    throw new Error('email booking field must be present, required, and not hidden');
  }
}

Type guard

function hasAccessibleEmailField(fields: unknown): boolean {
  if (!Array.isArray(fields)) return false;
  const email = fields.find(
    (f) => typeof f === 'object' && f !== null && (f as any).type === 'email' && (f as any).name === 'email'
  );
  return !!email && (email as any).required === true && !(email as any).hidden;
}

Try / catch

try {
  await api.patch(`/v2/event-types/${id}`, { bookingFields }, { headers: { 'cal-api-version': '2024-06-14' } });
} catch (e) {
  if (e.response?.status === 400 && e.response?.data?.message?.includes('Email booking field')) {
    // re-include the email system field with required:true, hidden:false
  } else throw e;
}

Prevention

When it happens

Trigger: POST or PATCH /v2/event-types (cal-api-version 2024-06-14) with bookingFields where the email field is marked hidden:true, required:false, or is omitted entirely while other bookingFields are supplied; setting the email field to optional; removing the email field from the array.

Common situations: Customizing the booking form and accidentally toggling email off; importing an event type config from an older version where email was optional; a frontend builder that lets users hide the email field; partial updates that include bookingFields without the email entry.

Related errors


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