HKUDS/Vibe-Trading · error · ValueError
source.kind must be 'prompt' or 'playbook'
Error message
source.kind must be 'prompt' or 'playbook'
What it means
draft.source.kind must be exactly 'prompt' or 'playbook'. Any other string (or a kind that is neither, e.g. 'template', 'query', 'workflow') falls into the else branch and raises.
Source
Thrown at agent/src/scheduled_research/service.py:150
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")
prompt = playbook.render(variables)
config["playbook"] = playbook_slug
else:
raise ValueError("source.kind must be 'prompt' or 'playbook'")
expression = str(schedule_spec.get("expression") or "").strip()
timezone = schedule_spec.get("timezone")
validate_schedule(expression)
if is_interval_schedule(expression):
validate_timezone_shape(timezone)
else:
validate_timezone(timezone)
next_run_at = now
if timezone is not None and not is_interval_schedule(expression):
next_run_at = next_due(expression, now, timezone)
end_at = _parse_end_at(draft.get("end_at"))
if end_at is not None and end_at <= now:
raise ValueError("end_at must be in the future")
if end_at is not None and next_run_at > end_at:
raise ValueError("the first scheduled run occurs after end_at")
View on GitHub (pinned to 80ffdda44c)
Solutions
- Use 'prompt' or 'playbook' exactly (lowercase)
- Omit kind entirely — it defaults to 'prompt'
- Align client and server on the supported kind enum after upgrades
Example fix
// before
{"source": {"kind": "Playbook", "playbook_slug": "x"}}
// after
{"source": {"kind": "playbook", "playbook_slug": "x"}} Defensive patterns
Strategy: validation
Validate before calling
assert draft.get("source", {}).get("kind", "prompt") in {"prompt", "playbook"} Type guard
def source_kind_valid(src: dict) -> bool:
return str(src.get("kind") or "prompt") in {"prompt", "playbook"} Try / catch
try:
propose_create(draft)
except ValueError as e:
if "source.kind" in str(e):
draft["source"]["kind"] = "prompt" # normalize fallback Prevention
- Expose kind as a closed enum in UI
- Lowercase/trim kind values client-side before submit
When it happens
Trigger: source={"kind":"workflow"}; typo like 'promt' or 'Playbook' (case-sensitive); passing a kind value from a newer/older schema.
Common situations: Client/server version drift adding new source kinds; user-typed kind values; case mismatches from locale-aware lowercasing.
Related errors
- unknown delivery status {raw_status!r}
- 'failure_kind' must be 'dispatch', 'schedule', or null
- 'source_type' must be 'prompt' or 'playbook'
- delivery.mode must be 'in_app', 'origin', or 'configured'
- invalid risk_tier: {req.risk_tier}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/26ba62d6b473bfa5.
Report an issue: GitHub.