calcom/cal.diy · error · BadRequestException
Invalid time range given - check the 'startTime' and 'endTim
Error message
Invalid time range given - check the 'startTime' and 'endTime' query parameters.
What it means
BadRequestException (HTTP 400) thrown by the slots controller when the underlying getAvailableSlots call throws an Error whose message contains the substring 'Invalid time range given'. The controller inspects the upstream error text and rewraps it as a 400 pointing the caller at the startTime/endTime query params. The original throw lives in the slots/getSlots domain logic and signals that the requested window is empty, inverted, or otherwise malformed.
Source
Thrown at apps/api/v2/src/modules/slots/slots-2024-04-15/controllers/slots.controller.ts:217
const { slots } = await this.slotsOutputService.getOutputSlots(
availableSlots,
query.duration,
query.eventTypeId,
query.slotFormat,
query.timeZone
);
return {
data: {
slots,
},
status: SUCCESS_STATUS,
};
} catch (error) {
if (error instanceof Error) {
if (error.message.includes("Invalid time range given")) {
throw new BadRequestException(
"Invalid time range given - check the 'startTime' and 'endTime' query parameters."
);
}
if (TRPC_ERROR_MAP[error.message as keyof typeof TRPC_ERROR_CODE]) {
throw new TRPCError({ code: error.message as TRPCErrorCode });
}
}
throw error;
}
}
}
View on GitHub (pinned to 176037d0af)
Solutions
- Ensure startTime is strictly before endTime and the window has positive duration when sent.
- Send full ISO-8601 instants (with Z) for both params, not bare dates.
- Validate client-side that endTime is in the future and after startTime before firing the request.
Example fix
// before
api.get('/slots/2024-04-15', { startTime: end, endTime: start }); // swapped
// after
const start = new Date();
const end = new Date(start.getTime() + 7 * 86400000);
api.get('/slots/2024-04-15', { startTime: start.toISOString(), endTime: end.toISOString() }); Defensive patterns
Strategy: validation
Validate before calling
function buildSlotsQuery(startTime: Date, endTime: Date) {
if (!(startTime.getTime() < endTime.getTime()))
throw new Error('startTime must be strictly before endTime');
if (endTime.getTime() <= Date.now())
throw new Error('endTime must be in the future');
return { startTime: startTime.toISOString(), endTime: endTime.toISOString() };
} Type guard
const isValidSlotRange = (start: Date, end: Date): boolean => start.getTime() < end.getTime() && end.getTime() > Date.now();
Prevention
- Always send full ISO instants with the Z suffix, not bare dates.
- Disable the slots request until start < end and end is in the future.
- Beware timezone normalization that can collapse a window to zero duration.
When it happens
Trigger: GET /v2/slots/2024-04-15 with startTime >= endTime, startTime/endTime outside allowed bounds, endTime in the past, or a window the engine considers degenerate (zero or negative duration after timezone normalization).
Common situations: Client computes endTime by subtracting instead of adding; passes startTime/endTime as date-only so the slot service sees them as equal midnight; timezone conversion flips the order; a date picker allowing the user to pick an end before the start.
Related errors
- Invalid slot format. Must be either 'range' or 'time'
- ${error.message as TRPCErrorCode}
- Event Type not found
- Invalid time range given - check the 'start' and 'end' query
- CustomThrottlerGuard - Too many requests. Please try again l
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/4d9060f0dc77e926.
Report an issue: GitHub.