HKUDS/Vibe-Trading · error · ValueError

cron field {atom!r} is out of range; expected {low}-{high}

Error message

cron field {atom!r} is out of range; expected {low}-{high}

What it means

After a range atom parses, both its endpoints must lie within the field's bounds (minutes 0-59, hours 0-23, day-of-month 1-31, month 1-12, day-of-week 0-6). A well-formed but out-of-bounds atom such as minute 60 or month 13 is rejected so the executor never computes impossible fire times.

Source

Thrown at agent/src/scheduled_research/models.py:66

        return
    if _CRON_STEP_RE.fullmatch(part):
        value = int(part[2:])
        if not low <= value <= high:
            raise ValueError(f"cron field {part!r} is out of range; expected {low}-{high}")
        return
    for atom in part.split(","):
        match = _CRON_ATOM_RE.fullmatch(atom)
        if match is None:
            raise ValueError(
                f"cron field {part!r} is not valid; each field must be *, */n, "
                f"or a comma-separated list of numbers and low-high ranges"
            )
        start = int(match.group(1))
        end = int(match.group(2)) if match.group(2) is not None else start
        if start > end:
            raise ValueError(f"cron range {atom!r} is reversed; expected low-high")
        if start < low or end > high:
            raise ValueError(f"cron field {atom!r} is out of range; expected {low}-{high}")


def parse_cron_field(part: str, low: int, high: int) -> Optional[Set[int]]:
    """Expand one validated cron field into its matching values.

    Kept beside :func:`validate_schedule` so the accepted grammar and the
    executor's evaluation of it can never drift apart.

    Args:
        part: One whitespace-delimited cron field (already validated).
        low: Inclusive lower bound of the field.
        high: Inclusive upper bound of the field.

    Returns:
        The set of matching integer values, or ``None`` for the ``*`` wildcard.
    """
    if part == "*":
        return None

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Check each atom against the field bounds; here day-of-week is 0-6 with Sunday=0, month is 1-12.
  2. Replace 7 with 0 for Sunday (or just list '0,6' for weekends).
  3. Run validate_schedule on every schedule before storing the job.

Example fix

# before
validate_schedule('0 0 * * 1-7')
# after
validate_schedule('0 0 * * 0-6')
Defensive patterns

Strategy: validation

Validate before calling

BOUNDS = [(0,59),(0,23),(1,31),(1,12),(0,6)]
for part, (lo, hi) in zip(schedule.split(), BOUNDS):
    for atom in part.split(','):
        for tok in atom.split('-'):
            assert lo <= int(tok) <= hi, f'{atom} out of {lo}-{hi}'

Try / catch

try:
    validate_schedule(schedule)
except ValueError as e:
    return bad_request(str(e))

Prevention

When it happens

Trigger: validate_schedule('61 * * * *') (minute 61), '0 0 32 * *' (day 32), '0 0 * 13 *' (month 13), or ranges like '0 0 * * 0-7' where 7 exceeds the 0-6 day-of-week bound.

Common situations: Day-of-week confusion: cron systems differ on whether Sunday is 0 or 7 and whether the bound is 0-6 or 1-7; this parser uses 0-6. Also hand-typed schedules with off-by-one month numbers (1-12, not 0-11).

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/89c5321040da035d. Report an issue: GitHub.