calcom/cal.diy · error · BadRequestException

Provided 'slotDuration' is not one of the possible lengths f

Error message

Provided 'slotDuration' is not one of the possible lengths for the event type. The possible lengths for this variable length event type are: ${eventTypeMetadata.multipleDuration.join(", ")}

What it means

Thrown by SlotsService.validateSlotDuration when reserving or updating a slot for a variable-length event type. Variable-length event types store their allowed durations as a number array in eventType.metadata.multipleDuration; the slotDuration you pass must be an element of that array or the request is rejected as a 400 BadRequest. The message dynamically lists the valid values so the client can correct the input.

Source

Thrown at apps/api/v2/src/modules/slots/slots-2024-09-04/services/slots.service.ts:225

    );

    if (overlappingReservation) {
      throw new UnprocessableEntityException(
        `This time slot is already reserved by another user. Please choose a different time.`
      );
    }
  }

  validateSlotDuration(eventType: EventType, inputSlotDuration: number) {
    const eventTypeMetadata = eventTypeMetadataSchema.parse(eventType.metadata);
    if (!eventTypeMetadata?.multipleDuration) {
      throw new BadRequestException(
        "You passed 'slotDuration' but this event type is not a variable length event type."
      );
    }

    if (!eventTypeMetadata.multipleDuration.includes(inputSlotDuration)) {
      throw new BadRequestException(
        `Provided 'slotDuration' is not one of the possible lengths for the event type. The possible lengths for this variable length event type are: ${eventTypeMetadata.multipleDuration.join(
          ", "
        )}`
      );
    }
  }

  async canSpecifyCustomReservationDuration(authUserId: number, eventType: EventType) {
    if (eventType.userId) {
      return await this.canSpecifyCustomReservationDurationIndividualEvent(authUserId, eventType.userId);
    }
    if (eventType.teamId) {
      return await this.canSpecifyCustomReservationDurationTeamEvent(authUserId, eventType.teamId);
    }
    return false;
  }

  async canSpecifyCustomReservationDurationIndividualEvent(authUserId: number, eventTypeOwnerId: number) {

View on GitHub (pinned to 176037d0af)

Solutions

  1. Fetch the event type first and read metadata.multipleDuration (exposed as lengthInMinutesOptions), then pass only a value present in that array.
  2. If any valid duration is acceptable, omit slotDuration entirely so the service falls back to eventType.length.
  3. Update the event type's metadata.multipleDuration to include the desired duration before reserving.

Example fix

// before
body: { eventTypeId, slotStart, slotDuration: 20 }

// after
const et = await api.getEventType(eventTypeId);
const allowed = et.lengthInMinutesOptions ?? [et.length];
const slotDuration = allowed.includes(20) ? 20 : et.length;
body: { eventTypeId, slotStart, slotDuration }
Defensive patterns

Strategy: validation

Validate before calling

import type { EventType } from './types';

function pickSlotDuration(
  et: Pick<EventType, 'length' | 'lengthInMinutesOptions'>,
  requested?: number
): number | undefined {
  if (requested === undefined) return undefined; // fall back to event type length
  const allowed = et.lengthInMinutesOptions ?? [];
  return allowed.includes(requested) ? requested : undefined;
}

// usage:
// const slotDuration = pickSlotDuration(eventType, body.slotDuration);
// if (body.slotDuration && slotDuration === undefined) { /* warn user */ }

Type guard

function isValidSlotDuration(
  et: { multipleDuration?: number[]; length: number },
  value: number
): boolean {
  const allowed = et.multipleDuration ?? [et.length];
  return allowed.includes(value);
}

Try / catch

try {
  await api.reserveSlot({ eventTypeId, slotStart, slotDuration });
} catch (e) {
  if (e.status === 400 && /possible lengths/.test(e.message)) {
    // parse allowed list from message, reprompt user to pick a valid duration
  } else throw e;
}

Prevention

When it happens

Trigger: POST /v2/event-types/{eventTypeId}/slots or PATCH /v2/slots/{uid} with a body containing slotDuration: 20 on an event type whose metadata.multipleDuration is [15,30,45]. The event type IS variable-length (multipleDuration exists), so the earlier 'not a variable length event type' guard is skipped, but 20 is not in the array.

Common situations: A UI dropdown of durations is desynced from the event type's configured multipleDuration after an admin edited the event type. An integration hardcodes a duration (e.g. 30) that was later removed from the event type. A client caches the duration list and sends a stale value after the event type was updated.

Related errors


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