HKUDS/Vibe-Trading · error · TypeError

'delivery' must be an object or null

Error message

'delivery' must be an object or null

What it means

Raised by ScheduledRun delivery from_dict (agent/src/scheduled_research/models.py:274) when the serialized 'delivery' payload is present but is not a JSON object (dict). The deserializer expects delivery to be an object or null so it can read keys like status, session_id, and attempts. Any other JSON type (string, list, number, boolean) is a type error.

Source

Thrown at agent/src/scheduled_research/models.py:274

    @classmethod
    def from_dict(cls, data: Optional[Dict[str, Any]]) -> "DeliveryRecord":
        """Reconstruct from a raw dict, treating absence as "never delivered".

        Args:
            data: A raw dict as produced by :meth:`to_dict`, or ``None`` for a
                record written before delivery existed.

        Returns:
            The reconstructed :class:`DeliveryRecord`.

        Raises:
            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"),

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Inspect the stored JSON and fix delivery to be an object: {"status": "none"} or null
  2. Find the writer that produced the malformed value and serialize the delivery dict as-is
  3. If hand-migrating, delete the delivery key to reset it to defaults
  4. Add a pre-load schema check on the store file before from_dict

Example fix

// before
{"delivery": "sent"}

// after
{"delivery": {"status": "sent"}}
Defensive patterns

Strategy: type-guard

Validate before calling

def valid_delivery(data):
    return data is None or isinstance(data, dict)

Type guard

from typing import Any, Optional, Dict

def as_delivery_dict(data: Any) -> Optional[Dict]:
    if data is None:
        return None
    if isinstance(data, dict):
        return data
    if isinstance(data, str):
        import json
        try:
            parsed = json.loads(data)
            return parsed if isinstance(parsed, dict) else None
        except json.JSONDecodeError:
            return None
    return None

Try / catch

try:
    delivery = DeliveryInfo.from_dict(raw)
except TypeError as exc:
    if "'delivery' must be an object" in str(exc):
        delivery = DeliveryInfo()  # reset to defaults
    else:
        raise

Prevention

When it happens

Trigger: Calling from_dict on a stored record where delivery was serialized as a JSON string like '"none"' or a list, e.g. {"delivery": "pending"} instead of {"delivery": {"status": "pending"}}. Empty/None data returns early and never raises.

Common situations: Hand-editing a persisted jobs.json; a migration script writing delivery as a flat string; double-encoding (json.dumps applied twice) producing a string payload; another tool writing the store with a different schema.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/f2b3e8bf03eab928. Report an issue: GitHub.