calcom/cal.diy · error · BadRequestException
Invalid start date
Error message
Invalid start date
What it means
A NestJS BadRequestException (HTTP 400) from SlotsService_2024_09_04.reserveSlot. Luxon's DateTime.fromISO(input.slotStart, {zone:'utc'}) produced an invalid DateTime (.isValid === false). The ReserveSlotInput DTO's @IsDateString may accept strings that luxon still rejects, so this is the runtime backstop. The slotStart must be a real instant.
Source
Thrown at apps/api/v2/src/modules/slots/slots-2024-09-04/services/slots.service.ts:121
if (!eventType) {
throw new NotFoundException(`Event Type with ID=${input.eventTypeId} not found`);
}
if (input.reservationDuration && authUserId) {
const canSpecifyCustomReservationDuration = await this.canSpecifyCustomReservationDuration(
authUserId,
eventType
);
if (!canSpecifyCustomReservationDuration) {
throw new ForbiddenException(
"authenticated user is not owner of event type, does not have memberships in common with owner of the event type, nor does belong to event type's team or org."
);
}
}
const startDate = DateTime.fromISO(input.slotStart, { zone: "utc" });
if (!startDate.isValid) {
throw new BadRequestException("Invalid start date");
}
if (input.slotDuration) {
this.validateSlotDuration(eventType, input.slotDuration);
}
const endDate = startDate.plus({ minutes: input.slotDuration ?? eventType.length });
if (!endDate.isValid) {
throw new BadRequestException("Invalid end date");
}
const booking = await this.slotsRepository.findActiveOverlappingBooking(
input.eventTypeId,
startDate.toJSDate(),
endDate.toJSDate()
);
if (eventType.seatsPerTimeSlot) {View on GitHub (pinned to 176037d0af)
Solutions
- Send slotStart as a full ISO 8601 UTC timestamp (new Date().toISOString()), e.g. '2024-09-04T09:00:00.000Z'.
- Client-side assert DateTime.fromISO(slotStart, {zone:'utc'}).isValid before posting.
- Use a slot start that was actually returned by GET /v2/slots rather than a hand-built string.
- Verify the value survives JSON serialization unchanged.
Example fix
// before
fetch('/v2/slots/reserve', { body: JSON.stringify({ eventTypeId, slotStart: '2024-09-04 09:00' }) });
// after
const slotStart = DateTime.fromISO('2024-09-04T09:00:00', { zone:'utc' }).toISO();
if (!slotStart) throw new Error('bad slotStart');
fetch('/v2/slots/reserve', { body: JSON.stringify({ eventTypeId, slotStart }) }); Defensive patterns
Strategy: validation
Validate before calling
import { DateTime } from 'luxon';
function toValidSlotStart(slotStart: unknown): string {
if (typeof slotStart !== 'string') throw new TypeError('slotStart must be an ISO string');
const dt = DateTime.fromISO(slotStart, { zone: 'utc' });
if (!dt.isValid) throw new RangeError(`Invalid slotStart: ${dt.invalidReason}`);
return dt.toISO()!;
}
const slotStart = toValidSlotStart(input.slotStart); Type guard
function isValidSlotStart(v: unknown): v is string {
return typeof v === 'string' && DateTime.fromISO(v, { zone: 'utc' }).isValid;
} Try / catch
try {
await cal.slots.reserve({ eventTypeId, slotStart });
} catch (e) {
if (e instanceof HttpError && e.statusCode === 400 && /start date/i.test(e.message)) {
throw new UserFacingError('Please choose a valid time slot.');
}
throw e;
} Prevention
- Always source slotStart from a GET /v2/slots response value.
- Send full ISO 8601 UTC strings (new Date().toISOString()).
- Run DateTime.fromISO(...).isValid before posting.
- Do not pass bare dates or locale-formatted strings.
When it happens
Trigger: POST /v2/slots/reserve with a slotStart that passes class-validator's date-string check but fails luxon parsing — e.g. a date-only '2024-09-04', an out-of-range component like month 13, or a string with invalid separators.
Common situations: Client sending a date without time; non-UTC offset that luxon disallows; copy-paste truncating the timestamp; passing a number coerced to string.
Related errors
- Invalid end date
- Invalid start date
- Invalid end date
- Could not adjust timezone for slot ${slot.time} with timezon
- Could not adjust timezone for slot end time ${slot.time} wit
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/543da94b456933db.
Report an issue: GitHub.