{"record":{"id":"dd9a1a421a2159aa","repo":"HKUDS/Vibe-Trading","slug":"timezone-must-be-a-non-empty-iana-timezone-key-or","errorCode":null,"errorMessage":"timezone must be a non-empty IANA timezone key or null","messagePattern":"timezone must be a non-empty IANA timezone key or null","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/scheduled_research/models.py","lineNumber":154,"sourceCode":"    if len(parts) != _CRON_PARTS:\n        raise ValueError(f\"schedule must be a positive integer (ms) or a 5-field cron string; got: {schedule!r}\")\n    for part, (low, high) in zip(parts, CRON_BOUNDS):\n        _validate_cron_field(part, low, high)\n\n\ndef validate_timezone_shape(tz: Optional[str]) -> None:\n    \"\"\"Raise ``ValueError`` when *tz* is not ``None`` or a non-empty string.\n\n    This is the persistence-level check: it deliberately does NOT resolve the\n    key, because resolvability depends on the host's timezone database. A\n    store written where a key resolved must keep loading and persisting on a\n    host where it does not; the executor surfaces the unresolvable key as a\n    per-job schedule failure instead.\n    \"\"\"\n    if tz is None:\n        return\n    if not isinstance(tz, str) or not tz.strip():\n        raise ValueError(\"timezone must be a non-empty IANA timezone key or null\")\n\n\ndef validate_timezone(tz: Optional[str]) -> None:\n    \"\"\"Raise ``ValueError`` when *tz* is not a resolvable IANA timezone key.\n\n    ``None`` is always valid and means legacy UTC semantics. Resolution goes\n    through :class:`zoneinfo.ZoneInfo`, so whatever validates here is exactly\n    what the executor can evaluate later.\n\n    Args:\n        tz: An IANA timezone key such as ``\"Pacific/Auckland\"``, or ``None``.\n\n    Raises:\n        ValueError: When *tz* is not ``None`` and cannot be resolved.\n    \"\"\"\n    validate_timezone_shape(tz)\n    if tz is None:\n        return","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/models.py#L136-L172","documentation":"validate_timezone_shape only checks the shape of the optional tz field on a scheduled job: it must be None (meaning legacy UTC) or a non-empty, non-whitespace string. The actual IANA resolution is deliberately deferred to validate_timezone so shape errors are caught even on hosts without the tz database.","triggerScenarios":"create_scheduled_run(tz='') or tz='   ' (whitespace), tz=123 or tz=[] (non-string), or a JSON body where 'tz': null vs missing-string handling forwards an empty value.","commonSituations":"Frontend forms submitting an empty timezone field as '' instead of omitting it; defaults like tz=os.getenv('JOB_TZ', '') that produce empty strings; JSON schemas typing tz loosely.","solutions":["Send null (or omit the field) for UTC semantics; send a real key like 'America/New_York' otherwise.","Normalize empty strings to None before calling the API: tz = tz or None.","Add a form/API-level check that timezone is null or a populated IANA string."],"exampleFix":"# before\ncreate_scheduled_run(..., tz='')\n# after\ncreate_scheduled_run(..., tz=None)  # or tz='America/New_York'","handlingStrategy":"validation","validationCode":"tz = tz.strip() if isinstance(tz, str) else None\nif not tz:\n    tz = None  # empty means UTC/legacy semantics\ncreate_scheduled_run(..., tz=tz)","typeGuard":"def is_valid_tz_shape(tz) -> bool:\n    return tz is None or (isinstance(tz, str) and bool(tz.strip()))","tryCatchPattern":"try:\n    create_scheduled_run(..., tz=tz)\nexcept ValueError as e:\n    if 'timezone' in str(e):\n        return bad_request(str(e))\n    raise","preventionTips":["Send null instead of '' for UTC.","Normalize frontend empty strings to None before API calls."],"tags":["python","timezone","validation","scheduler","config"],"backgroundTag":"invalid-configuration-value","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}