{"record":{"id":"5f9ae35658c6d40e","repo":"HKUDS/Vibe-Trading","slug":"today-must-be-an-iso-date-string-or-none-got-tod","errorCode":null,"errorMessage":"today must be an ISO date string or None, got {today!r}","messagePattern":"today must be an ISO date string or None, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/strategy_discovery/facade.py","lineNumber":113,"sourceCode":"        return None\n    return value\n\n\ndef _is_int(value: Any) -> bool:\n    \"\"\"True for real integers only (bool is explicitly excluded).\"\"\"\n    return isinstance(value, int) and not isinstance(value, bool)\n\n\ndef _parse_today(today: str | None) -> date:\n    \"\"\"Resolve the injected clock: ISO ``today`` string or the wall clock.\n\n    Raises ``ValueError`` for a non-string or unparseable ``today`` so the\n    caller can answer with an error envelope instead of a wrong date.\n    \"\"\"\n    if today is None:\n        return date.today()\n    if not isinstance(today, str):\n        raise ValueError(f\"today must be an ISO date string or None, got {today!r}\")\n    return date.fromisoformat(today.strip())\n\n\ndef _decay_fields(row, today: date) -> dict[str, Any]:\n    \"\"\"Read-time decay verdict for one evidence row (plan D1/D2).\n\n    Computed from the row's own ``date_ranges`` window end at query time —\n    never persisted. ``staleness_days`` (from ``last_verified``) is reported\n    alongside but NEVER gates: refreshing unchanged artifacts must not be\n    able to keep a row \"fresh\" forever.\n    \"\"\"\n    age = evidence_age_days(row.date_ranges, today)\n    status = classify_decay(row.date_ranges, today)\n    return {\n        \"decay_status\": status,\n        \"evidence_age_days\": age,\n        \"staleness_days\": staleness_days(row.last_verified, today),\n        \"_decay_warning\": decay_warning(status, age),","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/strategy_discovery/facade.py#L95-L131","documentation":"Raised by _parse_today in strategy_discovery/facade.py when the optional `today` argument is neither None nor a string (e.g. a date/datetime object passed directly). The facade accepts only an ISO date string or None (None means use date.today()). Passing any other type is rejected before date.fromisoformat is attempted.","triggerScenarios":"Calling query_strategies(today=date(2024,1,1)) or get_strategy_evidence(today=datetime.now()) — passing a date/datetime object or an int instead of an ISO string like '2024-01-01' or None.","commonSituations":"Callers already hold a datetime/date object from another API and pass it through unconverted; or pass an int timestamp assuming the facade parses it. Note date.fromisoformat itself will still raise ValueError for malformed strings, which is not caught here.","solutions":["Pass today=None to use the real current date","Pass an ISO string like '2024-01-31' (date.isoformat() output)","If you hold a date object, convert: today=d.isoformat()"],"exampleFix":"# before\nfacade.query_strategies(today=datetime(2024, 1, 31))\n# after\nfacade.query_strategies(today='2024-01-31')","handlingStrategy":"validation","validationCode":"from datetime import date\nif today is not None and not isinstance(today, str):\n    today = today.isoformat() if hasattr(today, 'isoformat') else None\nassert today is None or isinstance(today, str)","typeGuard":"def is_iso_date_or_none(v) -> bool:\n    if v is None: return True\n    if not isinstance(v, str): return False\n    try: date.fromisoformat(v.strip()); return True\n    except ValueError: return False","tryCatchPattern":"try:\n    facade.query_strategies(today=today)\nexcept ValueError as e:\n    if 'today must be' in str(e): logger.warning('bad today, retrying with None'); facade.query_strategies(today=None)\n    else: raise","preventionTips":["Always pass date.isoformat() output or None","Never pass datetime objects directly","Centralize today computation in one helper"],"tags":["python","date-parsing","valueerror"],"backgroundTag":"invalid-date-argument","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}