{"record":{"id":"63203c1f0d9e2693","repo":"HKUDS/Vibe-Trading","slug":"source-playbook-slug-is-required","errorCode":null,"errorMessage":"source.playbook_slug is required","messagePattern":"source\\.playbook_slug is required","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"agent/src/scheduled_research/service.py","lineNumber":142,"sourceCode":"    source = draft.get(\"source\")\n    schedule_spec = draft.get(\"schedule\")\n    delivery_spec = draft.get(\"delivery\") or {\"mode\": \"in_app\"}\n    if not isinstance(source, Mapping) or not isinstance(schedule_spec, Mapping):\n        raise ValueError(\"source and schedule must be objects\")\n    if not isinstance(delivery_spec, Mapping):\n        raise ValueError(\"delivery must be an object\")\n\n    source_type = str(source.get(\"kind\") or \"prompt\")\n    playbook_slug = None\n    config: dict[str, Any] = {}\n    if source_type == \"prompt\":\n        prompt = str(source.get(\"prompt\") or \"\").strip()\n        if not prompt:\n            raise ValueError(\"source.prompt is required\")\n    elif source_type == \"playbook\":\n        playbook_slug = str(source.get(\"playbook_slug\") or \"\").strip()\n        if not playbook_slug:\n            raise ValueError(\"source.playbook_slug is required\")\n        playbook = get_playbook(playbook_slug)\n        variables = source.get(\"variables\") or {}\n        if not isinstance(variables, Mapping):\n            raise ValueError(\"source.variables must be an object\")\n        prompt = playbook.render(variables)\n        config[\"playbook\"] = playbook_slug\n    else:\n        raise ValueError(\"source.kind must be 'prompt' or 'playbook'\")\n\n    expression = str(schedule_spec.get(\"expression\") or \"\").strip()\n    timezone = schedule_spec.get(\"timezone\")\n    validate_schedule(expression)\n    if is_interval_schedule(expression):\n        validate_timezone_shape(timezone)\n    else:\n        validate_timezone(timezone)\n    next_run_at = now\n    if timezone is not None and not is_interval_schedule(expression):","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/service.py#L124-L160","documentation":"When draft.source.kind is 'playbook', source.playbook_slug must be a non-empty string. The slug selects the playbook template whose rendered output becomes the job's prompt.","triggerScenarios":"source={\"kind\":\"playbook\"} with playbook_slug missing, empty, or whitespace-only; slug built from an unset variable.","commonSituations":"Playbook selection dropdown not required in the UI; slug strings with stray whitespace; renamed/deleted slugs referenced by value.","solutions":["Provide the exact playbook slug, e.g. source={\"kind\":\"playbook\",\"playbook_slug\":\"daily-digest\"}","Trim and verify the slug exists via get_playbook before submitting","Make playbook selection mandatory when kind='playbook'"],"exampleFix":"// before\n{\"source\": {\"kind\": \"playbook\", \"playbook_slug\": \"\"}}\n// after\n{\"source\": {\"kind\": \"playbook\", \"playbook_slug\": \"daily-digest\"}}","handlingStrategy":"validation","validationCode":"src = draft.get(\"source\", {})\nif src.get(\"kind\") == \"playbook\":\n    assert str(src.get(\"playbook_slug\") or \"\").strip(), \"source.playbook_slug is required\"","typeGuard":"def playbook_source_valid(src: dict) -> bool:\n    return src.get(\"kind\") != \"playbook\" or bool(str(src.get(\"playbook_slug\") or \"\").strip())","tryCatchPattern":"try:\n    propose_create(draft)\nexcept ValueError as e:\n    require_playbook_selection() if \"playbook_slug\" in str(e) else raise_","preventionTips":["Make playbook selection a required dropdown when kind='playbook'","Trim and existence-check slugs against the playbook registry before submit"],"tags":["scheduled-research","validation","playbook","required-field"],"backgroundTag":"missing-required-field","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}