calcom/cal.diy · error · UnprocessableEntityException
This time slot is already reserved by another user. Please c
Error message
This time slot is already reserved by another user. Please choose a different time.
What it means
A NestJS UnprocessableEntityException (HTTP 422) from SlotsService_2024_09_04.checkSlotOverlap. For non-round-robin events, the slotsRepository.getOverlappingSlotReservation returned an existing reservation for the same window. Another user is already holding the slot within the reservation window; only one active reservation is allowed.
Source
Thrown at apps/api/v2/src/modules/slots/slots-2024-09-04/services/slots.service.ts:210
eventType.id,
startDate.toISO(),
endDate.toISO(),
eventType.seatsPerTimeSlot !== null,
reservationDuration
);
return this.slotsOutputService.getReservationSlotCreated(slot, reservationDuration);
}
private async checkSlotOverlap(eventTypeId: number, startDate: string, endDate: string) {
const overlappingReservation = await this.slotsRepository.getOverlappingSlotReservation(
eventTypeId,
startDate,
endDate
);
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(
", "
)}`View on GitHub (pinned to 176037d0af)
Solutions
- Offer the user the next available slot from a freshly-fetched availability list.
- Wait for the existing reservation to expire (releaseAt) and retry if appropriate.
- Keep reservationDuration short to reduce overlap windows.
- Surface a 'slot just taken / held' message and refresh.
Example fix
// before
await reserve(eventTypeId, slotStart);
// after — refresh on 422 overlap and pick a different slot
try { await reserve(eventTypeId, slotStart); }
catch (e) {
if (e.status === 422 && /already reserved/i.test(e.message)) {
const next = await nextFreeSlot(eventTypeId);
await reserve(eventTypeId, next.start);
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// You cannot fully prevent a race; minimize the window by keeping reservationDuration short
// and re-checking availability right before reserve.
async function ensureSlotNotReserved(eventTypeId: number, slotStart: string) {
const slots = await cal.slots.list({ eventTypeId, start: slotStart, end: oneDayLater(slotStart) });
const hit = Object.values(slots).flat().find(s => s.start === slotStart && !s.away);
if (!hit) throw new UserFacingError('This time is being held by someone else.');
}
await ensureSlotNotReserved(eventTypeId, slotStart); Type guard
function isReservableSlot(slot: unknown): slot is { start: string } {
return typeof slot === 'object' && slot !== null
&& typeof (slot as any).start === 'string'
&& !(slot as any).away;
} Try / catch
try {
await cal.slots.reserve({ eventTypeId, slotStart });
} catch (e) {
if (e instanceof HttpError && e.statusCode === 422 && /already reserved/i.test(e.message)) {
const next = await nextFreeSlot(eventTypeId);
return cal.slots.reserve({ eventTypeId, slotStart: next.start });
}
throw e;
} Prevention
- Keep reservationDuration short to shrink overlap windows.
- Re-fetch availability immediately before reserve in popular slots.
- On 422 overlap, pick a different slot rather than retrying.
- Expire stale client-side holds before retrying.
When it happens
Trigger: POST /v2/slots/reserve where another reservation (a SelectedSlots row still within its releaseAt) overlaps the requested start/end. Common right after a popular slot opens or when two clients reserve concurrently.
Common situations: End user clicks the same time as another user; previous reservation not yet expired (default 5 min); retrying reserve after a network blip while the first reservation is still live; reservationDuration too long, blocking others.
Related errors
- Can't reserve a slot if the event is already booked.
- Booking with id=${input.eventTypeId} at ${input.slotStart} h
- reservationDuration can only be used for authenticated reque
- Event Type with ID=${input.eventTypeId} not found
- authenticated user is not owner of event type, does not have
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/59cc616afc006b8e.
Report an issue: GitHub.