{"record":{"id":"597b03893e0d1013","repo":"sansan0/TrendRadar","slug":"timeline-key","errorCode":null,"errorMessage":"timeline 缺少必须字段: {key}","messagePattern":"timeline 缺少必须字段: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"trendradar/core/scheduler.py","lineNumber":323,"sourceCode":"            date_str: 日期 YYYY-MM-DD\n        \"\"\"\n        self.storage.record_period_execution(date_str, period_key, action)\n\n    # ========================================\n    # 校验\n    # ========================================\n\n    def _validate_timeline(self, timeline: Dict[str, Any]) -> None:\n        \"\"\"\n        启动时校验 timeline 配置\n\n        Raises:\n            ValueError: 配置不合法时抛出\n        \"\"\"\n        required_top_keys = [\"default\", \"periods\", \"day_plans\", \"week_map\"]\n        for key in required_top_keys:\n            if key not in timeline:\n                raise ValueError(f\"timeline 缺少必须字段: {key}\")\n\n        # week_map 必须覆盖 1..7\n        for day in range(1, 8):\n            if day not in timeline[\"week_map\"]:\n                raise ValueError(f\"week_map 缺少星期映射: {day}\")\n\n        # day_plan 引用完整性\n        for day, plan_key in timeline[\"week_map\"].items():\n            if plan_key not in timeline[\"day_plans\"]:\n                raise ValueError(\n                    f\"week_map[{day}] 引用了不存在的 day_plan: {plan_key}\"\n                )\n\n        # period 引用完整性\n        for plan_key, plan in timeline[\"day_plans\"].items():\n            for period_key in plan.get(\"periods\", []):\n                if period_key not in timeline[\"periods\"]:\n                    raise ValueError(","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/sansan0/TrendRadar/blob/8ee26026ba6c11dec41a95fb3895a7162876caa1/trendradar/core/scheduler.py#L305-L341","documentation":"Raised by the scheduler's startup timeline validator when a required top-level key is missing from the timeline dict. The contract requires four keys: default, periods, day_plans, week_map. This fails fast at startup (or whenever _validate_timeline is called) rather than at resolution time, naming the first missing key.","triggerScenarios":"A custom timeline (preset: custom) that defines day_plans and week_map but omits 'default' or 'periods'; YAML indentation placing a section under the wrong parent; a programmatically built timeline missing a section.","commonSituations":"Starting from a minimal example timeline that skips optional-looking sections; upgrading configs where a key was renamed; typos in top-level key names ('defaults' vs 'default').","solutions":["Add the missing top-level key named in the message (empty dict is acceptable for periods/day_plans in most setups).","Copy the full skeleton from the shipped example timeline and fill it in.","Check YAML indentation — a section nested one level too deep becomes 'missing' at the top level.","Validate timelines in tests by calling _validate_timeline directly."],"exampleFix":"# before\ncustom:\n  default: {...}\n  day_plans: {...}\n  week_map: {...}\n# after (add periods)\ncustom:\n  default: {...}\n  periods: {}\n  day_plans: {...}\n  week_map: {...}","handlingStrategy":"validation","validationCode":"REQUIRED = [\"default\", \"periods\", \"day_plans\", \"week_map\"]\nmissing = [k for k in REQUIRED if k not in timeline]\nif missing:\n    raise ValueError(f\"timeline missing keys: {missing}\")\nscheduler = Scheduler(schedule_config, timeline_data)  # now safe","typeGuard":"def timeline_has_required_keys(t: dict) -> bool:\n    return all(k in t for k in (\"default\", \"periods\", \"day_plans\", \"week_map\"))","tryCatchPattern":"try:\n    scheduler = Scheduler(schedule_config, timeline_data)\nexcept ValueError as e:\n    if \"timeline 缺少必须字段\" in str(e):\n        raise SystemExit(f\"timeline config incomplete: {e}\")\n    raise","preventionTips":["Start custom timelines from the shipped example skeleton.","Add a CI lint that loads and validates the timeline YAML on every change."],"tags":["scheduler","config","missing-key","validation"],"backgroundTag":null,"analyzedSha":"8ee26026ba6c11dec41a95fb3895a7162876caa1","analyzedAt":"2026-08-15T01:42:18.084Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}