calcom/cal.diy · error · BadRequestException
Invalid slot format. Must be either 'range' or 'time'
Error message
Invalid slot format. Must be either 'range' or 'time'
What it means
BadRequestException (HTTP 400) thrown by SlotsOutputService.formatSlots() when the slotFormat query parameter is supplied but is not one of the SlotFormat enum values ('range' or 'time'). The guard runs Object.values(SlotFormat).includes(slotFormat); an unknown string is rejected. Omitting slotFormat entirely is allowed (defaults apply).
Source
Thrown at apps/api/v2/src/modules/slots/slots-2024-04-15/services/slots-output.service.ts:67
startTime: DateTime.fromISO(slot.startTime).setZone(timeZone).toISO() || "unknown-start-time",
endTime: DateTime.fromISO(slot.endTime).setZone(timeZone).toISO() || "unknown-end-time",
...(slot.attendees ? { attendees: slot.attendees } : {}),
...(slot.bookingUid ? { bookingUid: slot.bookingUid } : {}),
}));
return acc;
}, {} as Record<string, { startTime: string; endTime: string }[]>);
return { slots: formattedSlots };
}
private async formatSlots(
availableSlots: TimeSlots,
duration?: number,
eventTypeId?: number,
slotFormat?: SlotFormat
): Promise<RangeSlots> {
if (slotFormat && !Object.values(SlotFormat).includes(slotFormat)) {
throw new BadRequestException("Invalid slot format. Must be either 'range' or 'time'");
}
const slotDuration = await this.getDuration(duration, eventTypeId);
const slots = Object.entries(availableSlots.slots).reduce<
Record<string, { startTime: string; endTime: string; attendees?: number; bookingUid?: string }[]>
>((acc, [date, slots]) => {
acc[date] = (slots as { time: string; attendees?: number; bookingUid?: string }[]).map((slot) => {
const startTime = new Date(slot.time);
const endTime = new Date(startTime.getTime() + slotDuration * 60000);
return {
startTime: startTime.toISOString(),
endTime: endTime.toISOString(),
...(slot.attendees ? { attendees: slot.attendees } : {}),
...(slot.bookingUid ? { bookingUid: slot.bookingUid } : {}),
};
});
return acc;View on GitHub (pinned to 176037d0af)
Solutions
- Send slotFormat exactly as 'range' or 'time' (verify against the SlotFormat enum in the types package).
- Omit slotFormat if you want the default rather than guessing.
- Drive the value from a shared enum/const rather than a free-text string in the client.
Example fix
// before
api.get('/slots/2024-04-15', { slotFormat: 'ranges' }); // typo
// after — use the shared enum
import { SlotFormat } from '@calcom/types';
api.get('/slots/2024-04-15', { slotFormat: SlotFormat.Range }); // 'range' Defensive patterns
Strategy: type-guard
Validate before calling
const SLOT_FORMATS = ['range', 'time'] as const;
type SlotFormat = typeof SLOT_FORMATS[number];
function toSlotFormat(v: string): SlotFormat {
if (!SLOT_FORMATS.includes(v as SlotFormat)) throw new Error(`slotFormat must be one of ${SLOT_FORMATS.join(', ')}`);
return v as SlotFormat;
} Type guard
const isSlotFormat = (v: unknown): v is 'range' | 'time' => v === 'range' || v === 'time';
Prevention
- Bind the client's format picker to the SlotFormat enum, not free text.
- Omit slotFormat to use the default rather than guessing a string.
- Write the enum value in lowercase exactly as the server defines it.
When it happens
Trigger: GET /v2/slots/2024-04-15?slotFormat=ranges (typo/plural), slotFormat=range-time, slotFormat=friendly, or any casing mismatch like 'Range' if the enum is lowercase and case-sensitive.
Common situations: Client hardcoding a format string that drifted from the enum; a frontend toggle with a label value instead of the enum value; an integration guessing the format name; uppercase vs lowercase mismatch.
Related errors
- Invalid time range given - check the 'startTime' and 'endTim
- ${error.message as TRPCErrorCode}
- Event Type not found
- CustomThrottlerGuard - Too many requests. Please try again l
- CustomThrottlerGuard - Invalid API Key
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/0cdd48f63e28dee5.
Report an issue: GitHub.