HKUDS/Vibe-Trading · error · ValueError

cron field {part!r} is not valid; each field must be *, */n,

Error message

cron field {part!r} is not valid; each field must be *, */n, or a comma-separated list of numbers and low-high ranges

What it means

Each cron field must be '*', '*/n', or a comma-separated list of atoms matching a number or low-high range. Anything else — names (MON), L/W flags, @-shorthands, 6-field seconds, or stray characters — fails the atom regex and is rejected by this simplified 5-field parser.

Source

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

# either end of a range — is validated against these bounds so out-of-range
# values (e.g. minute ``99``) are rejected. Day-of-week uses the cron
# convention Sunday == 0; ``7`` is not accepted as a Sunday alias.
CRON_BOUNDS = ((0, 59), (0, 23), (1, 31), (1, 12), (0, 6))


def _validate_cron_field(part: str, low: int, high: int) -> None:
    """Raise ``ValueError`` when one cron field is malformed or out of range."""
    if part == "*":
        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:

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Convert names to numbers: MON->1, JAN->1, SUN->0 or 7 per your convention (here day-of-week is 0-6).
  2. Remove unsupported flags (@yearly, L, W, #, ?) and extra fields; this parser wants exactly 5 numeric fields.
  3. For fixed intervals, use the milliseconds form instead of cron.

Example fix

# before
validate_schedule('0 0 * * MON-FRI')
# after
validate_schedule('0 0 * * 1-5')
Defensive patterns

Strategy: validation

Validate before calling

import re
CRON_OK = re.compile(r"^(\*|(\*/\d+)|([0-9]+(-[0-9]+)?)(,[0-9]+(-[0-9]+)*)*)\s*$")
def fields_shape_ok(s: str) -> bool:
    parts = s.split()
    return len(parts) == 5 and all(CRON_OK.fullmatch(p) for p in parts)

Type guard

def is_supported_cron(s: str) -> bool:
    import re
    atom = r'(\d+(-\d+)?)'
    return bool(re.fullmatch(r'(\*|\*/\d+|' + atom + r'(,' + atom + r')*)', s))

Try / catch

try:
    validate_schedule(schedule)
except ValueError as e:
    raise HTTPError(400, str(e)) from e

Prevention

When it happens

Trigger: validate_schedule('0 0 * * MON'), '*/5 0 * * 1-5/2', '0 0 * * 1#3', or a Quartz-style '0 0 12 ? * MON-FR' string.

Common situations: Copying a cron string from crontab examples, Quartz, or cloud schedulers that support extended syntax; LLM- or user-supplied schedules using day names; assuming seconds fields exist.

Related errors


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