{"record":{"id":"00153ed667d59bba","repo":"home-assistant/core","slug":"end-time-before-start-time","errorCode":"end_time_before_start_time","errorMessage":"End time ({end_time}) must be after start time ({start_time})","messagePattern":"End time \\((.+?)\\) must be after start time \\((.+?)\\)","errorType":"validation","errorClass":"ServiceValidationError","httpStatus":null,"severity":"warning","filePath":"homeassistant/components/bsblan/services.py","lineNumber":91,"sourceCode":"    becomes: DaySchedule with two TimeSlot objects\n\n    None returns None (don't modify this day).\n    Empty list returns DaySchedule with empty slots (clear this day).\n    \"\"\"\n    if slots is None:\n        return None\n\n    if not slots:\n        return DaySchedule(slots=[])\n\n    time_slots = []\n    for slot in slots:\n        start_time = slot[\"start_time\"]\n        end_time = slot[\"end_time\"]\n\n        # Validate that end time is after start time\n        if end_time <= start_time:\n            raise ServiceValidationError(\n                translation_domain=DOMAIN,\n                translation_key=\"end_time_before_start_time\",\n                translation_placeholders={\n                    \"start_time\": start_time.strftime(\"%H:%M\"),\n                    \"end_time\": end_time.strftime(\"%H:%M\"),\n                },\n            )\n\n        time_slots.append(TimeSlot(start=start_time, end=end_time))\n        LOGGER.debug(\n            \"Created time slot: %s-%s\",\n            start_time.strftime(\"%H:%M\"),\n            end_time.strftime(\"%H:%M\"),\n        )\n\n    LOGGER.debug(\"Created DaySchedule with %d slots\", len(time_slots))\n    return DaySchedule(slots=time_slots)\n","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/home-assistant/core/blob/58a3fdb3ea0538617f0a07efcfba6294de64fd59/homeassistant/components/bsblan/services.py#L73-L109","documentation":"Validation error raised while building a weekly hot-water schedule from an action call: each time slot must have an end_time strictly after its start_time, compared as datetime.time values. It is a ServiceValidationError with translation key `end_time_before_start_time` and HH:MM placeholders, so the user gets an immediate, non-retrying error in the UI instead of a rejected device write.","triggerScenarios":"Calling `bsblan.set_hot_water_schedule` (or a YAML service call) with a slot where `end_time <= start_time`, e.g. start 22:00 end 06:00 intended as an overnight slot — cross-midnight ranges are not supported by this validator.","commonSituations":"Users modeling overnight heating windows as a single slot; AM/PM mixups in 12-hour input widgets; copying schedules from systems that allow wrap-around slots.","solutions":["Split the overnight window into two slots: 22:00–23:59 and 00:00–06:00.","Double-check AM/PM in the time picker before submitting.","Ensure each slot's end time is strictly greater than start; equal times are also rejected."],"exampleFix":"// before (invalid)\nslots: [{start_time: \"22:00:00\", end_time: \"06:00:00\"}]\n// after (valid — split across midnight)\nslots: [\n  {start_time: \"22:00:00\", end_time: \"23:59:00\"},\n  {start_time: \"00:00:00\", end_time: \"06:00:00\"},\n]","handlingStrategy":"validation","validationCode":"def slot_is_valid(start: dt.time, end: dt.time) -> bool:\n    return end > start\n\nassert all(slot_is_valid(s[\"start_time\"], s[\"end_time\"]) for s in slots)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate slot ordering client-side before calling the action.","Split overnight windows at midnight instead of wrap-around slots.","Prefer 24-hour time pickers to avoid AM/PM confusion."],"tags":["home-assistant","bsblan","schedule","validation","service-action"],"backgroundTag":null,"analyzedSha":"58a3fdb3ea0538617f0a07efcfba6294de64fd59","analyzedAt":"2026-08-14T20:54:38.818Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}