{"record":{"id":"47e9f8b83af7848b","repo":"HKUDS/Vibe-Trading","slug":"end-at-must-be-in-the-future-47e9f8","errorCode":null,"errorMessage":"end_at must be in the future","messagePattern":"end_at must be in the future","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"agent/src/scheduled_research/service.py","lineNumber":165,"sourceCode":"        prompt = playbook.render(variables)\n        config[\"playbook\"] = playbook_slug\n    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'\")","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/service.py#L147-L183","documentation":"The parsed end_at (epoch ms) is not strictly in the future relative to the job creation time. Jobs that would already be expired at creation are rejected as nonsensical.","triggerScenarios":"Passing an end_at in the past (epoch ms or dated string); clock skew between client and server; long-held drafts submitted after their intended end date.","commonSituations":"Client clocks ahead/behind server; retrying an old draft payload; DST or year typos (e.g. 2025 vs 2026) making the date past.","solutions":["Set end_at to a future timestamp or omit it for no end","Sync clocks / use server time when computing end_at from relative offsets","On retry, regenerate end_at rather than resending the original value"],"exampleFix":"// before\n{\"end_at\": 1600000000000}\n// after\n{\"end_at\": 3900000000000}  // future, or omit","handlingStrategy":"validation","validationCode":"now_ms = int(time.time() * 1000)\nend = draft.get(\"end_at\")\nassert end is None or (isinstance(end, int) and not isinstance(end, bool) and end > now_ms)","typeGuard":"def end_at_in_future(v) -> bool:\n    if v is None or v == \"\":\n        return True\n    if isinstance(v, bool) or not isinstance(v, int):\n        return False\n    return v > int(time.time() * 1000)","tryCatchPattern":"try:\n    propose_create(draft)\nexcept ValueError as e:\n    if \"end_at must be in the future\" in str(e):\n        draft.pop(\"end_at\", None); retry()","preventionTips":["Compute end_at at submit time, not at draft-creation time","Regenerate end_at on retries; keep client clocks NTP-synced"],"tags":["scheduled-research","validation","end-at","time"],"backgroundTag":"expired-timestamp-value","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}