{"record":{"id":"e033f1b7ff193f8f","repo":"HKUDS/Vibe-Trading","slug":"the-first-scheduled-run-occurs-after-end-at-e033f1","errorCode":null,"errorMessage":"the first scheduled run occurs after end_at","messagePattern":"the first scheduled run occurs after end_at","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"agent/src/scheduled_research/service.py","lineNumber":167,"sourceCode":"    else:\n        raise ValueError(\"source.kind must be 'prompt' or 'playbook'\")\n\n    expression = str(schedule_spec.get(\"expression\") or \"\").strip()\n    timezone = schedule_spec.get(\"timezone\")\n    validate_schedule(expression)\n    if is_interval_schedule(expression):\n        validate_timezone_shape(timezone)\n    else:\n        validate_timezone(timezone)\n    next_run_at = now\n    if timezone is not None and not is_interval_schedule(expression):\n        next_run_at = next_due(expression, now, timezone)\n\n    end_at = _parse_end_at(draft.get(\"end_at\"))\n    if end_at is not None and end_at <= now:\n        raise ValueError(\"end_at must be in the future\")\n    if end_at is not None and next_run_at > end_at:\n        raise ValueError(\"the first scheduled run occurs after end_at\")\n\n    mode = str(delivery_spec.get(\"mode\") or \"in_app\")\n    delivery_channel = delivery_target = target_ref = target_label = None\n    if mode == \"configured\":\n        target_ref = str(delivery_spec.get(\"target_ref\") or \"\").strip()\n        if not target_ref:\n            raise ValueError(\"delivery.target_ref is required for configured delivery\")\n        target = resolve_delivery_target(target_ref)\n        delivery_channel, delivery_target = target.channel, target.target\n        target_label = target.label\n    elif mode == \"origin\":\n        delivery_channel, delivery_target, target_ref, target_label = _origin_target(\n            session_id\n        )\n    elif mode != \"in_app\":\n        raise ValueError(\"delivery.mode must be 'in_app', 'origin', or 'configured'\")\n\n    return ScheduledResearchJob(","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/service.py#L149-L185","documentation":"The job's first scheduled run (next_run_at, computed from the schedule expression/timezone, or 'now' for interval schedules) falls after end_at, so the job could never fire before expiring.","triggerScenarios":"A weekly cron with an end_at 3 days out; interval schedules where next_run_at defaults to now but end_at is in the past millisecond boundary; timezone shifts pushing the next due date beyond end_at.","commonSituations":"Users setting short end dates on infrequent schedules; timezone conversions moving next_due across the end boundary; test fixtures with tiny end_at windows.","solutions":["Extend end_at beyond the first occurrence, or omit it","Use a more frequent schedule expression so a run occurs before end_at","Double-check timezone: compute next_due in the job's timezone to verify it precedes end_at"],"exampleFix":"// before\n{\"schedule\": {\"expression\": \"0 9 * * 1\"}, \"end_at\": \"<3 days from now>\"}\n// after\n{\"schedule\": {\"expression\": \"0 9 * * 1\"}, \"end_at\": \"<10 days from now>\"}","handlingStrategy":"validation","validationCode":"from scheduled_research.schedule import next_due, is_interval_schedule\nnra = now_ms if is_interval_schedule(expr) else next_due(expr, now_ms, tz)\nassert end_at is None or nra <= end_at, \"first run after end_at\"","typeGuard":"def schedule_fits_window(expr: str, tz, end_at: int | None, now: int) -> bool:\n    return end_at is None or (now if is_interval_schedule(expr) else next_due(expr, now, tz)) <= end_at","tryCatchPattern":"try:\n    propose_create(draft)\nexcept ValueError as e:\n    if \"after end_at\" in str(e):\n        draft.pop(\"end_at\", None); retry()  # or extend end_at","preventionTips":["Pre-compute the first occurrence and compare with end_at client-side","Avoid tight end windows on infrequent cron expressions"],"tags":["scheduled-research","validation","schedule","end-at"],"backgroundTag":"schedule-window-invalid","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}