{"record":{"id":"450e6d50e9094e38","repo":"HKUDS/Vibe-Trading","slug":"cron-range-atom-r-is-reversed-expected-low-high","errorCode":null,"errorMessage":"cron range {atom!r} is reversed; expected low-high","messagePattern":"cron range (.+?) is reversed; expected low-high","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/scheduled_research/models.py","lineNumber":64,"sourceCode":"    \"\"\"Raise ``ValueError`` when one cron field is malformed or out of range.\"\"\"\n    if part == \"*\":\n        return\n    if _CRON_STEP_RE.fullmatch(part):\n        value = int(part[2:])\n        if not low <= value <= high:\n            raise ValueError(f\"cron field {part!r} is out of range; expected {low}-{high}\")\n        return\n    for atom in part.split(\",\"):\n        match = _CRON_ATOM_RE.fullmatch(atom)\n        if match is None:\n            raise ValueError(\n                f\"cron field {part!r} is not valid; each field must be *, */n, \"\n                f\"or a comma-separated list of numbers and low-high ranges\"\n            )\n        start = int(match.group(1))\n        end = int(match.group(2)) if match.group(2) is not None else start\n        if start > end:\n            raise ValueError(f\"cron range {atom!r} is reversed; expected low-high\")\n        if start < low or end > high:\n            raise ValueError(f\"cron field {atom!r} is out of range; expected {low}-{high}\")\n\n\ndef parse_cron_field(part: str, low: int, high: int) -> Optional[Set[int]]:\n    \"\"\"Expand one validated cron field into its matching values.\n\n    Kept beside :func:`validate_schedule` so the accepted grammar and the\n    executor's evaluation of it can never drift apart.\n\n    Args:\n        part: One whitespace-delimited cron field (already validated).\n        low: Inclusive lower bound of the field.\n        high: Inclusive upper bound of the field.\n\n    Returns:\n        The set of matching integer values, or ``None`` for the ``*`` wildcard.\n    \"\"\"","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/models.py#L46-L82","documentation":"Within a cron field atom, a range low-high must have low <= high. A reversed range like 5-1 matches the atom grammar but denotes an empty set of values, which is almost always an authoring mistake, so it is rejected explicitly rather than silently matching nothing.","triggerScenarios":"validate_schedule('0 0 * * 5-1') (Friday-to-Monday style wrap), '50-10 * * * *' for minutes, or ranges generated by min/max arguments passed in the wrong order.","commonSituations":"Trying to express a wrap-around range (e.g. 'weekend plus Monday' or '10pm-2am') which standard cron cannot express as a single range; programmatic range building with swapped bounds.","solutions":["Split wrap-around ranges into explicit lists: '22-23,0-2' for 22:00-02:00, '0,5-6' for Sunday plus Fri-Sat.","Sort generated bounds before formatting a range.","Prefer listing individual values when unsure."],"exampleFix":"# before\nvalidate_schedule('0 22-2 * * *')\n# after\nvalidate_schedule('0 22-23,0-2 * * *')","handlingStrategy":"validation","validationCode":"for atom in part.split(','):\n    if '-' in atom:\n        lo, hi = map(int, atom.split('-'))\n        assert lo <= hi, f'reversed range: {atom}'\nvalidate_schedule(schedule)","typeGuard":null,"tryCatchPattern":"try:\n    validate_schedule(schedule)\nexcept ValueError as e:\n    return {'error': str(e)}, 400","preventionTips":["Split wrap-around ranges into explicit lists (e.g. '22-23,0-2').","Sort generated range bounds before formatting."],"tags":["python","cron","validation","scheduler"],"backgroundTag":"cron-expression-invalid","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}