HKUDS/Vibe-Trading · error · ValueError
source and schedule must be objects
Error message
source and schedule must be objects
What it means
The draft's 'source' and 'schedule' fields must both be JSON objects (Mappings). One of them is missing, null, or a scalar/array, so the builder cannot read kind/prompt or expression/timezone from it.
Source
Thrown at agent/src/scheduled_research/service.py:128
return channel, target, None, "当前会话"
def build_job_from_draft(
draft: Mapping[str, Any],
*,
session_id: str | None = None,
now_ms: int | None = None,
) -> ScheduledResearchJob:
"""Validate the public draft and build a persisted-model job."""
now = int(time.time() * 1000) if now_ms is None else now_ms
title = str(draft.get("title") or "").strip()
if not title:
raise ValueError("title is required")
source = draft.get("source")
schedule_spec = draft.get("schedule")
delivery_spec = draft.get("delivery") or {"mode": "in_app"}
if not isinstance(source, Mapping) or not isinstance(schedule_spec, Mapping):
raise ValueError("source and schedule must be objects")
if not isinstance(delivery_spec, Mapping):
raise ValueError("delivery must be an object")
source_type = str(source.get("kind") or "prompt")
playbook_slug = None
config: dict[str, Any] = {}
if source_type == "prompt":
prompt = str(source.get("prompt") or "").strip()
if not prompt:
raise ValueError("source.prompt is required")
elif source_type == "playbook":
playbook_slug = str(source.get("playbook_slug") or "").strip()
if not playbook_slug:
raise ValueError("source.playbook_slug is required")
playbook = get_playbook(playbook_slug)
variables = source.get("variables") or {}
if not isinstance(variables, Mapping):
raise ValueError("source.variables must be an object")View on GitHub (pinned to 80ffdda44c)
Solutions
- Wrap values in objects: source={"kind":"prompt","prompt":"..."} and schedule={"expression":"0 9 * * *"}
- Check the current draft schema in service.build_job_from_draft
- Add a client-side schema validator before submit
Example fix
// before
{"source": "summarize HN", "schedule": "0 9 * * *"}
// after
{"source": {"kind": "prompt", "prompt": "summarize HN"}, "schedule": {"expression": "0 9 * * *"}} Defensive patterns
Strategy: type-guard
Validate before calling
from collections.abc import Mapping
assert isinstance(draft.get("source"), Mapping) and isinstance(draft.get("schedule"), Mapping) Type guard
from collections.abc import Mapping
def draft_source_schedule_valid(d: dict) -> bool:
return isinstance(d.get("source"), Mapping) and isinstance(d.get("schedule"), Mapping) Try / catch
try:
build_job_from_draft(draft)
except ValueError as e:
return schema_error(str(e)) # map to 400 for the client Prevention
- Use a typed schema (pydantic/zod) for the draft payload
- Keep clients and server on the same draft schema version
When it happens
Trigger: Sending draft with source as a string prompt instead of {kind:'prompt',prompt:...}; schedule as a cron string instead of {expression:...}; either field omitted or null.
Common situations: API shape mismatch after version upgrade; clients simplifying the nested schema; docs examples that show flattened forms.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- delivery must be an object
- timezone {tz!r} is not a recognized IANA timezone key
- unknown delivery status {raw_status!r}
- 'failure_kind' must be 'dispatch', 'schedule', or null
- 'source_type' must be 'prompt' or 'playbook'
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/c6333e63811aa790.
Report an issue: GitHub.