calcom/cal.diy · warning · BadRequestException
Invalid ${key} hours. Expected value between 0 and 23
Error message
Invalid ${key} hours. Expected value between 0 and 23 What it means
Thrown by transformStringToDate when the parsed hours value from the time portion falls outside the valid 0–23 range. The hours component is extracted from the first colon-separated segment of the time portion and converted via Number(). Values like 24, -1, or NaN-producing strings trigger HTTP 400. The ${key} interpolation identifies which field (startTime or endTime) had the invalid hours.
Source
Thrown at apps/api/v2/src/platform/schedules/schedules_2024_04_15/inputs/create-availability.input.ts:46
const dateTimeParts = value.split("T");
if (dateTimeParts.length !== 2) {
throw new BadRequestException(
`Invalid datestring format. Expected format(ISO8061): 2025-04-12T13:17:56.324Z. Received: ${value}`
);
}
const timePart = dateTimeParts[1].split(".")[0]; // Removes milliseconds
const parts = timePart.split(":");
if (parts.length !== 3) {
throw new BadRequestException(
`Invalid time format. Expected format(ISO8061): 2025-0412T13:17:56.324Z. Received: ${value}`
);
}
const [hours, minutes, seconds] = parts.map(Number);
if (hours < 0 || hours > 23) {
throw new BadRequestException(`Invalid ${key} hours. Expected value between 0 and 23`);
}
if (minutes < 0 || minutes > 59) {
throw new BadRequestException(`Invalid ${key} minutes. Expected value between 0 and 59`);
}
if (seconds < 0 || seconds > 59) {
throw new BadRequestException(`Invalid ${key} seconds. Expected value between 0 and 59`);
}
return new Date(new Date().setUTCHours(hours, minutes, seconds, 0));
}
View on GitHub (pinned to 176037d0af)
Solutions
- Verify the hours value in the time string is between 0 and 23 (24-hour format).
- Use a Date object and toISOString() to guarantee valid hour values from the start.
- Add a client-side assertion: if (hours < 0 || hours > 23) throw before sending.
Example fix
// before "startTime": "2025-04-12T24:00:00.000Z" // after "startTime": new Date(2025, 3, 12, 0, 0, 0).toISOString()
Defensive patterns
Strategy: validation
Validate before calling
function validateHours(isoString: string, fieldName: string): void {
const timePart = isoString.split('T')[1]?.split('.')[0];
const hours = Number(timePart?.split(':')[0]);
if (isNaN(hours) || hours < 0 || hours > 23) {
throw new Error(`${fieldName}: hours must be 0-23, got ${hours}`);
}
}
validateHours(item.startTime, 'startTime'); Type guard
function hasValidHours(isoString: string): boolean {
const timePart = isoString.split('T')[1]?.split('.')[0];
if (!timePart) return false;
const hours = Number(timePart.split(':')[0]);
return !isNaN(hours) && hours >= 0 && hours <= 23;
} Prevention
- Use Date objects and toISOString() to produce valid hour values automatically.
- Never perform hour arithmetic that can exceed 23 without using modular overflow.
- Validate the hours component client-side before sending the request.
- Be careful with timezone conversions that may push hours past 23.
When it happens
Trigger: Sending a time like '24:00:00' (hours = 24); sending '-01:00:00'; sending a non-numeric hours token like 'ab:00:00' which Number() converts to NaN (NaN < 0 is false but NaN > 23 is also false, so NaN may actually slip through — this is a latent bug).
Common situations: Client-side arithmetic produces an hours value ≥ 24 after timezone conversion; 12-hour clock formatting without AM/PM conversion sends hours like 13+ incorrectly; manual time string construction with an off-by-one error.
Related errors
- Invalid ${key} minutes. Expected value between 0 and 59
- Invalid ${key} seconds. Expected value between 0 and 59
- Missing ${key}. Expected value is in ISO8061 format e.g. 202
- Invalid datestring format. Expected format(ISO8061): 2025-04
- Invalid time format. Expected format(ISO8061): 2025-0412T13:
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/4eaf20ecfc5c0eb4.
Report an issue: GitHub.