HKUDS/Vibe-Trading · error · TypeError
'delivery.updated_at' must be an integer (epoch ms) or null
Error message
'delivery.updated_at' must be an integer (epoch ms) or null
What it means
Raised by delivery from_dict (agent/src/scheduled_research/models.py:286) when the optional 'updated_at' field in the delivery object is present but is not an integer. Timestamps are stored as epoch milliseconds (ints); float seconds, ISO strings, or Date objects fail this check. null is accepted.
Source
Thrown at agent/src/scheduled_research/models.py:286
TypeError: If a present field has the wrong type.
ValueError: If ``status`` is not a recognized value.
"""
if not data:
return cls()
if not isinstance(data, dict):
raise TypeError("'delivery' must be an object or null")
raw_status = data.get("status", DeliveryStatus.NONE.value)
try:
status = DeliveryStatus(raw_status)
except ValueError as exc:
raise ValueError(f"unknown delivery status {raw_status!r}") from exc
for name in ("session_id", "key", "error", "provider_message_id"):
value = data.get(name)
if value is not None and not isinstance(value, str):
raise TypeError(f"'delivery.{name}' must be a string or null")
updated_at = data.get("updated_at")
if updated_at is not None and not isinstance(updated_at, int):
raise TypeError("'delivery.updated_at' must be an integer (epoch ms) or null")
attempts = data.get("attempts", 0)
if isinstance(attempts, bool) or not isinstance(attempts, int) or attempts < 0:
raise TypeError("'delivery.attempts' must be a non-negative integer")
return cls(
status=status,
session_id=data.get("session_id"),
key=data.get("key"),
error=data.get("error"),
attempts=attempts,
updated_at=updated_at,
provider_message_id=data.get("provider_message_id"),
)
# ---------------------------------------------------------------------------
# Data model
# ---------------------------------------------------------------------------
View on GitHub (pinned to 80ffdda44c)
Solutions
- Convert to epoch ms int: int(dt.timestamp() * 1000)
- Round/convert floats: int(round(value))
- Serialize datetimes explicitly to int ms rather than relying on default JSON encoders
- Omit the field (null) if you don't track it
Example fix
// before
delivery = {"updated_at": datetime.now(timezone.utc).isoformat()}
// after
from datetime import datetime, timezone
delivery = {"updated_at": int(datetime.now(timezone.utc).timestamp() * 1000)} Defensive patterns
Strategy: validation
Validate before calling
from datetime import datetime, timezone
def to_epoch_ms(dt):
return int(dt.timestamp() * 1000) if dt else None
def updated_at_ok(v):
return v is None or (isinstance(v, int) and not isinstance(v, bool)) Type guard
from typing import Any, Optional
def as_epoch_ms(value: Any) -> Optional[int]:
if value is None:
return None
if isinstance(value, bool):
return None
if isinstance(value, (int, float)):
return int(value)
if isinstance(value, str):
try:
return int(datetime.fromisoformat(value.replace("Z", "+00:00")).timestamp() * 1000)
except ValueError:
return None
return None Try / catch
try:
delivery = DeliveryInfo.from_dict(raw)
except TypeError as exc:
if "updated_at" in str(exc):
raw = dict(raw); raw["updated_at"] = None
delivery = DeliveryInfo.from_dict(raw)
else:
raise Prevention
- Use one to_epoch_ms helper for every persisted timestamp
- Never rely on default JSON encoders for datetime fields
- Decide seconds vs milliseconds once and stick to milliseconds
When it happens
Trigger: delivery = {"updated_at": "2026-01-01T00:00:00Z"} or {"updated_at": 1767225600.5} or {"updated_at": 1767225600000/n} where n makes it a float.
Common situations: Writing epoch seconds instead of milliseconds; serializing datetime objects as ISO strings via a generic JSON encoder; floats creeping in from arithmetic on timestamps.
Related errors
- 'next_run_at' and 'created_at' must be integers (epoch ms)
- 'last_run_at' must be an integer (epoch ms) or null
- 'end_at' must be an integer (epoch ms) or null
- 'delivery' must be an object or null
- unknown delivery status {raw_status!r}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/ddfe284cf23a64de.
Report an issue: GitHub.