{"record":{"id":"0d3d19ee09e3af95","repo":"sansan0/TrendRadar","slug":"week-map-day-day-plan-plan-key","errorCode":null,"errorMessage":"week_map[{day}] 引用了不存在的 day_plan: {plan_key}","messagePattern":"week_map\\[(.+?)\\] 引用了不存在的 day_plan: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"trendradar/core/scheduler.py","lineNumber":333,"sourceCode":"        启动时校验 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(\n                        f\"day_plan[{plan_key}] 引用了不存在的 period: {period_key}\"\n                    )\n\n        # 时间格式校验\n        for period_key, period in timeline[\"periods\"].items():\n            if \"start\" not in period or \"end\" not in period:\n                raise ValueError(\n                    f\"period '{period_key}' 缺少 start 或 end 字段\"\n                )\n            self._validate_hhmm(period[\"start\"], f\"{period_key}.start\")","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/sansan0/TrendRadar/blob/8ee26026ba6c11dec41a95fb3895a7162876caa1/trendradar/core/scheduler.py#L315-L351","documentation":"Raised by _validate_timeline's referential-integrity pass when a week_map entry points at a day_plan key that is not defined. It iterates every (day, plan_key) pair and fails on the first dangling reference. This is the startup-time twin of the runtime error at scheduler.py:135.","triggerScenarios":"week_map: {1: workday} while day_plans defines only 'weekday'; renaming or deleting a day_plan without updating week_map; a plan key with a trailing space or different casing.","commonSituations":"Rename refactors applied to day_plans but not week_map; YAML duplicate-key issues silently dropping a plan; case mismatches ('Work' vs 'work').","solutions":["Align names: either restore/define the day_plan key week_map references, or update week_map to an existing key.","Check for invisible whitespace and casing differences between the two sections.","Keep renames atomic — update week_map in the same edit as day_plans."],"exampleFix":"# before\nweek_map: {1: workday}\nday_plans: {workdays: {periods: []}}\n# after\nweek_map: {1: workdays}\nday_plans: {workdays: {periods: []}}","handlingStrategy":"validation","validationCode":"plans = timeline.get(\"day_plans\", {})\nfor day, key in timeline.get(\"week_map\", {}).items():\n    if key not in plans:\n        raise ValueError(f\"week_map[{day}] references undefined day_plan '{key}'\")","typeGuard":"def no_dangling_day_plan_refs(t: dict) -> bool:\n    plans = set(t.get(\"day_plans\", {}))\n    return set(t.get(\"week_map\", {}).values()) <= plans","tryCatchPattern":"try:\n    scheduler = Scheduler(schedule_config, timeline_data)\nexcept ValueError as e:\n    if \"引用了不存在的 day_plan\" in str(e):\n        raise SystemExit(f\"schedule config error: {e}; align week_map and day_plans names\")\n    raise","preventionTips":["Update week_map references in the same commit as day_plan renames.","Validate referential integrity in a config-lint test."],"tags":["scheduler","config","dangling-reference","validation"],"backgroundTag":null,"analyzedSha":"8ee26026ba6c11dec41a95fb3895a7162876caa1","analyzedAt":"2026-08-15T01:42:18.084Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}