{"record":{"id":"68756ed883d4c3d2","repo":"sansan0/TrendRadar","slug":"preset-join-presets-keys","errorCode":null,"errorMessage":"未知的预设模板: '{preset}'，可选值: {', '.join(presets.keys())}, custom","messagePattern":"未知的预设模板: '(.+?)'，可选值: (.+?), custom","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"trendradar/core/scheduler.py","lineNumber":90,"sourceCode":"        # 加载并构建最终 timeline\n        self.timeline = self._build_timeline(schedule_config, timeline_data)\n        if self.enabled:\n            self._validate_timeline(self.timeline)\n\n    def _build_timeline(\n        self,\n        schedule_config: Dict[str, Any],\n        timeline_data: Dict[str, Any],\n    ) -> Dict[str, Any]:\n        \"\"\"从 preset 或 custom 构建 timeline\"\"\"\n        preset = schedule_config.get(\"preset\", \"always_on\")\n\n        if preset == \"custom\":\n            timeline = copy.deepcopy(timeline_data.get(\"custom\", {}))\n        else:\n            presets = timeline_data.get(\"presets\", {})\n            if preset not in presets:\n                raise ValueError(\n                    f\"未知的预设模板: '{preset}'，可选值: \"\n                    f\"{', '.join(presets.keys())}, custom\"\n                )\n            timeline = copy.deepcopy(presets[preset])\n\n        # 确保 periods 是 dict（可能为空 {}）\n        if timeline.get(\"periods\") is None:\n            timeline[\"periods\"] = {}\n\n        return timeline\n\n    def resolve(self) -> ResolvedSchedule:\n        \"\"\"\n        解析当前时间对应的调度配置\n\n        Returns:\n            ResolvedSchedule 包含当前应执行的行为\n        \"\"\"","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/sansan0/TrendRadar/blob/8ee26026ba6c11dec41a95fb3895a7162876caa1/trendradar/core/scheduler.py#L72-L108","documentation":"Raised by the scheduler's timeline builder when schedule_config.preset is neither 'custom' nor a key of timeline_data.presets. The builder deep-copies either the custom timeline or a named preset; an unknown name aborts with the full list of valid preset names appended.","triggerScenarios":"Setting preset: \"work_hours\" in schedule config when presets only defines e.g. always_on/nightly; typo in the preset name; using a preset introduced in a newer version against an older timeline config that lacks it.","commonSituations":"Editing config/schedule YAML by hand and misspelling the preset; upgrading trendradar and referencing a newly documented preset with an un-upgraded timeline file; mixing preset names across projects.","solutions":["Use one of the preset names listed in the error message (plus 'custom').","For a bespoke schedule, set preset: custom and define the custom timeline block.","After upgrades, re-check the shipped timeline config for newly added presets."],"exampleFix":"# schedule config\n# before\npreset: work_hour   # typo\n# after\npreset: work_hours  # exact name from presets map, or 'custom'","handlingStrategy":"validation","validationCode":"preset = schedule_config.get(\"preset\", \"always_on\")\nknown = set(timeline_data.get(\"presets\", {}).keys()) | {\"custom\"}\nif preset not in known:\n    raise ValueError(f\"unknown preset {preset!r}; valid: {sorted(known)}\")\ntimeline = build_timeline(schedule_config, timeline_data)","typeGuard":"def is_known_preset(name: str, timeline_data: dict) -> bool:\n    return name == \"custom\" or name in timeline_data.get(\"presets\", {})","tryCatchPattern":"try:\n    scheduler = Scheduler(schedule_config, timeline_data)\nexcept ValueError as e:\n    if \"未知的预设模板\" in str(e):\n        schedule_config[\"preset\"] = \"always_on\"  # safe default, then rebuild\n        scheduler = Scheduler(schedule_config, timeline_data)\n    else:\n        raise","preventionTips":["Validate preset names against the presets map before constructing the scheduler.","Re-validate schedule configs after upgrading trendradar — preset lists change."],"tags":["config","scheduler","preset","validation"],"backgroundTag":null,"analyzedSha":"8ee26026ba6c11dec41a95fb3895a7162876caa1","analyzedAt":"2026-08-15T01:42:18.084Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}