sansan0/TrendRadar · error · ValueError

day_plan[{plan_key}] 引用了不存在的 period: {period_key}

Error message

day_plan[{plan_key}] 引用了不存在的 period: {period_key}

What it means

Raised by _validate_timeline when a period referenced from a day_plan lacks a 'start' or 'end' field. Every entry under timeline.periods must define both boundaries in HH:MM; the check runs after referential integrity, so the period key exists but is malformed.

Source

Thrown at trendradar/core/scheduler.py:341

                raise ValueError(f"timeline 缺少必须字段: {key}")

        # week_map 必须覆盖 1..7
        for day in range(1, 8):
            if day not in timeline["week_map"]:
                raise ValueError(f"week_map 缺少星期映射: {day}")

        # day_plan 引用完整性
        for day, plan_key in timeline["week_map"].items():
            if plan_key not in timeline["day_plans"]:
                raise ValueError(
                    f"week_map[{day}] 引用了不存在的 day_plan: {plan_key}"
                )

        # period 引用完整性
        for plan_key, plan in timeline["day_plans"].items():
            for period_key in plan.get("periods", []):
                if period_key not in timeline["periods"]:
                    raise ValueError(
                        f"day_plan[{plan_key}] 引用了不存在的 period: {period_key}"
                    )

        # 时间格式校验
        for period_key, period in timeline["periods"].items():
            if "start" not in period or "end" not in period:
                raise ValueError(
                    f"period '{period_key}' 缺少 start 或 end 字段"
                )
            self._validate_hhmm(period["start"], f"{period_key}.start")
            self._validate_hhmm(period["end"], f"{period_key}.end")
            if period["start"] == period["end"]:
                raise ValueError(
                    f"period '{period_key}' 的 start 与 end 不能相同: {period['start']}"
                )

        # 检查冲突策略下的重叠
        policy = timeline.get("overlap", {}).get("policy", "error_on_overlap")

View on GitHub (pinned to 8ee26026ba)

Solutions

  1. Add both start and end (HH:MM strings) to the period named in the message.
  2. Use the exact field names 'start' and 'end'.
  3. For cross-midnight spans, end may be earlier than start (supported) but must still be present.

Example fix

# before
periods:
  night: {start: "22:00"}
# after
periods:
  night: {start: "22:00", end: "06:00"}
Defensive patterns

Strategy: validation

Validate before calling

import re
HHMM = re.compile(r"^([01]\d|2[0-3]):[0-5]\d$")
for key, p in timeline.get("periods", {}).items():
    if "start" not in p or "end" not in p:
        raise ValueError(f"period '{key}' missing start/end")
    assert HHMM.match(p["start"]) and HHMM.match(p["end"]), f"period '{key}' bad HH:MM"

Type guard

def is_wellformed_period(p: dict) -> bool:
    return (
        isinstance(p, dict)
        and isinstance(p.get("start"), str)
        and isinstance(p.get("end"), str)
    )

Try / catch

try:
    scheduler = Scheduler(schedule_config, timeline_data)
except ValueError as e:
    if "缺少 start 或 end" in str(e):
        raise SystemExit(f"timeline period incomplete: {e}")
    raise

Prevention

When it happens

Trigger: Defining periods: {night: {start: "22:00"}} without end; naming the fields differently ('from'/'to' instead of 'start'/'end'); a period set to null in YAML.

Common situations: Translating a schedule from another tool whose field names differ; YAML where a value line was accidentally deleted; copying an example and not replacing placeholder keys.

Related errors


AI-assisted analysis of sansan0/TrendRadar@8ee26026ba (2026-08-15). Data as JSON: /api/errors/c7ef2eb970beca1e. Report an issue: GitHub.