{"record":{"id":"6cac814f32cbf39f","repo":"HKUDS/DeepTutor","slug":"unknown-timezone-schedule-tz-r","errorCode":null,"errorMessage":"unknown timezone {schedule.tz!r}","messagePattern":"unknown timezone (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/cron/service.py","lineNumber":170,"sourceCode":"    \"\"\"Reject schedules that could never run (raises ValueError).\"\"\"\n    if schedule.kind == \"at\":\n        if not schedule.at_ms:\n            raise ValueError(\"'at' schedules need a time\")\n        if schedule.at_ms <= _now_ms():\n            raise ValueError(\"'at' time is in the past\")\n        return\n    if schedule.kind == \"every\":\n        if not schedule.every_seconds or schedule.every_seconds < 30:\n            raise ValueError(\"'every' interval must be at least 30 seconds\")\n        return\n    if schedule.kind == \"cron\":\n        if schedule.tz:\n            try:\n                from zoneinfo import ZoneInfo\n\n                ZoneInfo(schedule.tz)\n            except Exception:\n                raise ValueError(f\"unknown timezone {schedule.tz!r}\") from None\n        # Raises ValueError on bad/unsupported expressions.\n        if compute_next_run(schedule, _now_ms()) is None:\n            raise ValueError(f\"cron expression {schedule.expr!r} never fires\")\n        return\n    raise ValueError(f\"unknown schedule kind {schedule.kind!r}\")\n\n\nclass CronService:\n    \"\"\"Single-process job store + scheduler.\"\"\"\n\n    def __init__(\n        self,\n        store_path: Path,\n        on_job: Callable[[CronJob], Awaitable[tuple[str, str | None]]] | None = None,\n    ) -> None:\n        \"\"\"``on_job`` returns ``(status, error)`` with status ok/error/skipped.\"\"\"\n        self.store_path = store_path\n        self.on_job = on_job","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/cron/service.py#L152-L188","documentation":"validate_schedule catches any exception from zoneinfo.ZoneInfo(schedule.tz) on cron schedules and re-raises ValueError('unknown timezone ...'). The tz string must be an IANA zone name resolvable via system tzdata; anything else fails.","triggerScenarios":"CronSchedule(kind=\"cron\", expr=\"0 9 * * *\", tz=\"America/New_Yorkk\") or non-IANA strings like 'EST'/'UTC+2'; also containers missing /usr/share/zoneinfo or the tzdata package.","commonSituations":"Typo'd IANA names; offset-style strings instead of region/city; minimal Docker images (alpine/slim) without tzdata; Windows lacking the tzdata pip package.","solutions":["Use an exact IANA name like 'Europe/Berlin' or 'America/New_York'","Install tzdata: apt-get install -y tzdata (or apk add tzdata; pip install tzdata on Windows/slim)","Verify with ZoneInfo(name) in a shell before deploying the schedule"],"exampleFix":"# before\nsched = CronSchedule(kind=\"cron\", expr=\"0 9 * * *\", tz=\"CET\")\n# after\nsched = CronSchedule(kind=\"cron\", expr=\"0 9 * * *\", tz=\"Europe/Paris\")\n# slim Docker: RUN apt-get update && apt-get install -y tzdata","handlingStrategy":"validation","validationCode":"from zoneinfo import ZoneInfo\n\ndef valid_tz(name: str | None) -> bool:\n    if not name:\n        return True\n    try:\n        ZoneInfo(name)\n        return True\n    except Exception:\n        return False\n\nassert valid_tz(schedule.tz), f\"bad tz {schedule.tz!r}\"","typeGuard":null,"tryCatchPattern":"try:\n    svc.add_job(schedule, ...)\nexcept ValueError as e:\n    if \"unknown timezone\" in str(e):\n        schedule.tz = \"UTC\"\n        svc.add_job(schedule, ...)\n    else:\n        raise","preventionTips":["Offer an IANA-picker in the UI, not free text","Install tzdata in slim images","Pre-validate tz on config load"],"tags":["cron","timezone","zoneinfo","validation"],"backgroundTag":"invalid-timezone-name","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}