{"record":{"id":"1f3c9add6b02bdf8","repo":"HKUDS/Vibe-Trading","slug":"schedule-must-be-a-positive-integer-ms-or-a-5-fi","errorCode":null,"errorMessage":"schedule must be a positive integer (ms) or a 5-field cron string; got: {schedule!r}","messagePattern":"schedule must be a positive integer \\(ms\\) or a 5-field cron string; got: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/scheduled_research/models.py","lineNumber":137,"sourceCode":"        schedule: Either a positive integer string (interval-ms) or a\n            simplified 5-field cron expression.\n\n    Raises:\n        ValueError: When the schedule does not match either accepted form.\n    \"\"\"\n    if not schedule or not isinstance(schedule, str):\n        raise ValueError(\"schedule must be a non-empty string\")\n\n    if _INTERVAL_MS_RE.fullmatch(schedule.strip()):\n        # 15 digits ≈ 31,000 years in milliseconds — anything longer is not a\n        # usable interval and would only feed int() conversion of huge strings.\n        if len(schedule.strip()) > 15:\n            raise ValueError(\"interval is too large; expected at most 15 digits of milliseconds\")\n        return  # valid interval\n\n    parts = schedule.strip().split()\n    if len(parts) != _CRON_PARTS:\n        raise ValueError(f\"schedule must be a positive integer (ms) or a 5-field cron string; got: {schedule!r}\")\n    for part, (low, high) in zip(parts, CRON_BOUNDS):\n        _validate_cron_field(part, low, high)\n\n\ndef validate_timezone_shape(tz: Optional[str]) -> None:\n    \"\"\"Raise ``ValueError`` when *tz* is not ``None`` or a non-empty string.\n\n    This is the persistence-level check: it deliberately does NOT resolve the\n    key, because resolvability depends on the host's timezone database. A\n    store written where a key resolved must keep loading and persisting on a\n    host where it does not; the executor surfaces the unresolvable key as a\n    per-job schedule failure instead.\n    \"\"\"\n    if tz is None:\n        return\n    if not isinstance(tz, str) or not tz.strip():\n        raise ValueError(\"timezone must be a non-empty IANA timezone key or null\")\n","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/models.py#L119-L155","documentation":"After the interval form is ruled out, the schedule must split into exactly 5 whitespace-separated cron fields (minute hour day-of-month month day-of-week). Any other field count — 6-field Quartz strings with seconds, single-word shorthands like '@daily', or truncated strings — is rejected.","triggerScenarios":"validate_schedule('* * * * * *') (6 fields), validate_schedule('@hourly'), validate_schedule('0 9 * *') (4 fields), or tabs/multiple spaces are fine but wrong field count still fails.","commonSituations":"Copying a Quartz/CloudWatch/EventBridge expression that includes a seconds field; using @-shorthands from Vixie cron; trailing truncation when a schedule string is cut off in config or logging.","solutions":["Rewrite as exactly 5 fields: drop the leading seconds field, translate @daily to '0 0 * * *', @hourly to '0 * * * *'.","For fixed-rate schedules, use the millisecond interval form instead of a 6-field expression.","Validate user-supplied schedules with validate_schedule at ingestion time."],"exampleFix":"# before\nvalidate_schedule('0 */2 * * * *')\n# after\nvalidate_schedule('*/120 * * * *')  # or '7200000' ms","handlingStrategy":"validation","validationCode":"parts = schedule.split()\nif len(parts) == 6:\n    schedule = ' '.join(parts[1:])  # drop Quartz seconds field\nSHORTHAND = {'@hourly': '0 * * * *', '@daily': '0 0 * * *', '@weekly': '0 0 * * 0'}\nschedule = SHORTHAND.get(schedule, schedule)\nvalidate_schedule(schedule)","typeGuard":"def is_five_field_cron(s: str) -> bool:\n    return isinstance(s, str) and len(s.split()) == 5","tryCatchPattern":"try:\n    validate_schedule(schedule)\nexcept ValueError as e:\n    return bad_request(f'invalid schedule: {e}')","preventionTips":["Expect exactly 5 fields; drop leading seconds from Quartz strings.","Translate @-shorthands before submission.","Use ms-interval strings for fixed rates."],"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"}