{"record":{"id":"7271acf8d67a100f","repo":"mantinedev/mantine","slug":"mantine-schedule-event-end-date-is-before-start","errorCode":null,"errorMessage":"[@mantine/schedule] Event end date is before start date for event id: ${eventData.id}","messagePattern":"\\[@mantine/schedule\\] Event end date is before start date for event id: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@mantine/schedule/src/utils/validate-event/validate-event.ts","lineNumber":14,"sourceCode":"import dayjs from 'dayjs';\nimport { ScheduleEventData } from '../../types';\n\nexport function validateEvent(eventData: ScheduleEventData) {\n  if (!dayjs(eventData.start).isValid()) {\n    throw new Error(`[@mantine/schedule] Invalid start date for event id: ${eventData.id}`);\n  }\n\n  if (!dayjs(eventData.end).isValid()) {\n    throw new Error(`[@mantine/schedule] Invalid end date for event id: ${eventData.id}`);\n  }\n\n  if (dayjs(eventData.end).isBefore(dayjs(eventData.start))) {\n    throw new Error(\n      `[@mantine/schedule] Event end date is before start date for event id: ${eventData.id}`\n    );\n  }\n\n  return eventData;\n}\n","sourceCodeStart":1,"sourceCodeEnd":21,"githubUrl":"https://github.com/mantinedev/mantine/blob/8a284e2c2c53a9cb6f39f5dc389bf41b7a2073f8/packages/@mantine/schedule/src/utils/validate-event/validate-event.ts#L1-L21","documentation":"validateEvent requires events to be chronological: dayjs(event.end).isBefore(dayjs(event.start)) must be false. A negative duration makes overlapping/layout calculations meaningless, so the library throws with the offending event id.","triggerScenarios":"end earlier than start (e.g. start '2025-01-10T15:00' with end '2025-01-10T14:00'), often after timezone conversion shifts one bound, or after swapping start/end fields when mapping API data.","commonSituations":"DST/timezone shifts making a same-instant range appear inverted, swapped API field mapping, drag-to-resize gesture producing a negative range, or 12h/24h AM-PM mix-ups in a form.","solutions":["Swap start/end if they are inverted at the mapping layer","Validate and clamp ranges (end = max(start, end)) before rendering","For timezone bugs, normalise both bounds to the same timezone/UTC before comparison"],"exampleFix":"// before\n{ id: '1', start: '2025-01-10T15:00', end: '2025-01-10T14:00' }\n\n// after\n{ id: '1', start: '2025-01-10T14:00', end: '2025-01-10T15:00' }","handlingStrategy":"validation","validationCode":"const normalized = events.map((e) => {\n  const start = dayjs(e.start);\n  const end = dayjs(e.end);\n  return end.isBefore(start) ? { ...e, start: end.toISOString(), end: start.toISOString() } : e;\n});","typeGuard":"const isChronological = (e: ScheduleEventData): boolean =>\n  !dayjs(e.end).isBefore(dayjs(e.start));","tryCatchPattern":null,"preventionTips":["Clamp end = max(start, end) when mapping API data","Test timezone-sensitive ranges around DST boundaries","Swap fields at the mapping layer if the backend order is unreliable"],"tags":["mantine","schedule","date-validation","date-range"],"backgroundTag":"invalid-date-range","analyzedSha":"8a284e2c2c53a9cb6f39f5dc389bf41b7a2073f8","analyzedAt":"2026-08-28T10:25:51.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}