{"record":{"id":"1811e7f06420df8f","repo":"HKUDS/Vibe-Trading","slug":"end-at-must-be-rfc3339-text-or-epoch-milliseconds","errorCode":null,"errorMessage":"end_at must be RFC3339 text or epoch milliseconds","messagePattern":"end_at must be RFC3339 text or epoch milliseconds","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"agent/src/scheduled_research/service.py","lineNumber":81,"sourceCode":"    host = sys.modules.get(\"api_server\") or sys.modules.get(\"agent.api_server\")\n    executor = getattr(host, \"_scheduled_research_executor\", None) if host else None\n    if executor is None:\n        try:\n            from src.api import scheduled_routes\n\n            executor = scheduled_routes._scheduled_research_executor\n        except Exception:\n            executor = None\n    if executor is not None:\n        running = bool(executor.is_running)\n    return {\"enabled\": enabled, \"running\": running, \"executable\": enabled and running}\n\n\ndef _parse_end_at(value: Any) -> int | None:\n    if value in (None, \"\"):\n        return None\n    if isinstance(value, bool):\n        raise ValueError(\"end_at must be RFC3339 text or epoch milliseconds\")\n    if isinstance(value, int):\n        return value\n    if not isinstance(value, str):\n        raise ValueError(\"end_at must be RFC3339 text or epoch milliseconds\")\n    try:\n        parsed = datetime.fromisoformat(value.strip().replace(\"Z\", \"+00:00\"))\n    except ValueError as exc:\n        raise ValueError(\"end_at must be a valid RFC3339 timestamp\") from exc\n    if parsed.tzinfo is None:\n        raise ValueError(\"end_at must include an explicit timezone offset\")\n    return int(parsed.timestamp() * 1000)\n\n\ndef _origin_target(session_id: str | None) -> tuple[str, str, str | None, str]:\n    if not session_id:\n        raise ValueError(\"origin delivery requires the originating session\")\n    host = sys.modules.get(\"api_server\") or sys.modules.get(\"agent.api_server\")\n    service = (","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/service.py#L63-L99","documentation":"_parse_end_at rejects the end_at draft field when it is a boolean. Since bool is a subclass of int in Python, the explicit check exists to stop `true`/`false` JSON values from being silently treated as epoch 1/0 milliseconds.","triggerScenarios":"Passing end_at: true or end_at: false in the draft JSON (e.g. from a checkbox or feature flag leaking into the payload); any JSON boolean where a timestamp is expected.","commonSituations":"Frontend forms binding a toggle/checkbox to the end_at field; YAML/JSON config where an unquoted yes/no becomes a boolean; defaulting end_at to a flag instead of null.","solutions":["Send end_at as null/omitted for no end date, an RFC3339 string, or epoch milliseconds int","Audit the client code that serializes the draft for boolean coercion","If using YAML, quote values like \"true\" so they stay strings, or better, use real timestamps"],"exampleFix":"// before\n{\"end_at\": true}\n// after\n{\"end_at\": null}  // or \"2026-12-31T00:00:00Z\" or 1798761600000","handlingStrategy":"validation","validationCode":"assert draft.get(\"end_at\") is None or isinstance(draft.get(\"end_at\"), (str, int)) and not isinstance(draft.get(\"end_at\"), bool)","typeGuard":"def valid_end_at_type(v) -> bool:\n    return v is None or v == \"\" or (isinstance(v, (int, str)) and not isinstance(v, bool))","tryCatchPattern":"try:\n    build_job_from_draft(draft)\nexcept ValueError as e:\n    if \"RFC3339 text or epoch milliseconds\" in str(e):\n        fix_end_at_field()","preventionTips":["Never bind booleans to end_at in forms","Schema-validate drafts client-side (string|int|null only)"],"tags":["scheduled-research","validation","end-at","type-confusion"],"backgroundTag":"field-type-validation-failed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}