{"record":{"id":"28643e8a17166f26","repo":"HKUDS/Vibe-Trading","slug":"period-must-be-string-got-type-period-name","errorCode":null,"errorMessage":"period must be string, got {type(period).__name__}","messagePattern":"period must be string, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/tools/alpha_bench_tool.py","lineNumber":83,"sourceCode":"# Universe + period parsing\n# ---------------------------------------------------------------------------\n\n_PERIOD_YEAR = re.compile(r\"^(\\d{4})-(\\d{4})$\")\n_PERIOD_DATE = re.compile(r\"^(\\d{4}-\\d{2}-\\d{2})/(\\d{4}-\\d{2}-\\d{2})$\")\n\n# Universe → (market_key, universe_meta_tag). Only the listed universes have a\n# defined contract; everything else returns \"not yet implemented\".\n_UNIVERSE_TAG = {\n    \"csi300\": \"equity_cn\",\n    \"sp500\": \"equity_us\",\n    \"btc-usdt\": \"crypto\",\n}\n\n\ndef _parse_period(period: str) -> tuple[str, str]:\n    \"\"\"Return (start_date, end_date) as YYYY-MM-DD strings.\"\"\"\n    if not isinstance(period, str):\n        raise ValueError(f\"period must be string, got {type(period).__name__}\")\n    m = _PERIOD_DATE.match(period)\n    if m:\n        start, end = m.group(1), m.group(2)\n    else:\n        m = _PERIOD_YEAR.match(period)\n        if m:\n            start, end = f\"{m.group(1)}-01-01\", f\"{m.group(2)}-12-31\"\n        else:\n            raise ValueError(\n                f\"period {period!r} must be YYYY-YYYY or YYYY-MM-DD/YYYY-MM-DD\"\n            )\n    # Match backtest loaders.validate_date_range: reject inverted ranges.\n    if pd.Timestamp(start) > pd.Timestamp(end):\n        raise ValueError(f\"start_date ({start}) > end_date ({end})\")\n    return start, end\n\n\ndef _load_universe_panel(","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/tools/alpha_bench_tool.py#L65-L101","documentation":"_parse_period in alpha_bench_tool requires the period argument to be a str. Passing any other type (int, None, dict, datetime) raises this immediately, before regex matching is attempted.","triggerScenarios":"Calling alpha_bench / kick_off_bench / kick_off_compare / _load_universe_panel with period=None, period=2023, or a pandas Timestamp / datetime object instead of a string.","commonSituations":"Tool schemas where the LLM emits a number for a year-only period; passing datetime objects from downstream code; optional kwargs that default to None being forwarded unconditionally.","solutions":["Convert the value to str before calling (e.g. str(period) for scalars)","Add a JSON-schema 'type':'string' constraint on the tool's period parameter","Default the parameter explicitly (e.g. '2020-2023') instead of letting None through"],"exampleFix":"// before\nresult = alpha_bench(universe='csi300', period=None)\n// after\nresult = alpha_bench(universe='csi300', period='2020-2023')","handlingStrategy":"type-guard","validationCode":"period = period if isinstance(period, str) else str(period)\nassert isinstance(period, str) and period","typeGuard":"def is_period_str(p: object) -> bool:\n    return isinstance(p, str) and len(p) > 0","tryCatchPattern":"try:\n    alpha_bench(universe=u, period=period)\nexcept ValueError as e:\n    if 'period must be string' in str(e):\n        period = str(period); retry()\n    else: raise","preventionTips":["Declare string types in tool JSON schemas","Never forward Optional[str] without coalescing to a default"],"tags":["type-validation","api-parameters","alpha-bench"],"backgroundTag":"wrong-argument-type","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}