HKUDS/Vibe-Trading · error · ValueError
timezone must be a non-empty IANA timezone key or null
Error message
timezone must be a non-empty IANA timezone key or null
What it means
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.
Source
Thrown at agent/src/scheduled_research/models.py:154
if len(parts) != _CRON_PARTS:
raise ValueError(f"schedule must be a positive integer (ms) or a 5-field cron string; got: {schedule!r}")
for part, (low, high) in zip(parts, CRON_BOUNDS):
_validate_cron_field(part, low, high)
def validate_timezone_shape(tz: Optional[str]) -> None:
"""Raise ``ValueError`` when *tz* is not ``None`` or a non-empty string.
This is the persistence-level check: it deliberately does NOT resolve the
key, because resolvability depends on the host's timezone database. A
store written where a key resolved must keep loading and persisting on a
host where it does not; the executor surfaces the unresolvable key as a
per-job schedule failure instead.
"""
if tz is None:
return
if not isinstance(tz, str) or not tz.strip():
raise ValueError("timezone must be a non-empty IANA timezone key or null")
def validate_timezone(tz: Optional[str]) -> None:
"""Raise ``ValueError`` when *tz* is not a resolvable IANA timezone key.
``None`` is always valid and means legacy UTC semantics. Resolution goes
through :class:`zoneinfo.ZoneInfo`, so whatever validates here is exactly
what the executor can evaluate later.
Args:
tz: An IANA timezone key such as ``"Pacific/Auckland"``, or ``None``.
Raises:
ValueError: When *tz* is not ``None`` and cannot be resolved.
"""
validate_timezone_shape(tz)
if tz is None:
returnView on GitHub (pinned to 80ffdda44c)
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.
Example fix
# before create_scheduled_run(..., tz='') # after create_scheduled_run(..., tz=None) # or tz='America/New_York'
Defensive patterns
Strategy: validation
Validate before calling
tz = tz.strip() if isinstance(tz, str) else None
if not tz:
tz = None # empty means UTC/legacy semantics
create_scheduled_run(..., tz=tz) Type guard
def is_valid_tz_shape(tz) -> bool:
return tz is None or (isinstance(tz, str) and bool(tz.strip())) Try / catch
try:
create_scheduled_run(..., tz=tz)
except ValueError as e:
if 'timezone' in str(e):
return bad_request(str(e))
raise Prevention
- Send null instead of '' for UTC.
- Normalize frontend empty strings to None before API calls.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid configuration value" and "Unsupported/Unknown setting value" errors: why libraries reject your config strings, numbers, and types — this error's family across 30 libraries.
Related errors
- display_currency must be USD or CNY
- portfolio source labels must contain 1 to 80 printable chara
- cron schedule has no matching time within search window: {sc
- cron field {part!r} is out of range; expected {low}-{high}
- cron field {part!r} is not valid; each field must be *, */n,
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/dd9a1a421a2159aa.
Report an issue: GitHub.