{"record":{"id":"89214848859f39fe","repo":"HKUDS/Vibe-Trading","slug":"playbook-path-key-r-must-be-a-non-empty-list","errorCode":null,"errorMessage":"playbook {path}: {key!r} must be a non-empty list of strings","messagePattern":"playbook (.+?): (.+?) must be a non-empty list of strings","errorType":"validation","errorClass":"PlaybookError","httpStatus":null,"severity":"error","filePath":"agent/src/scheduled_research/playbooks.py","lineNumber":243,"sourceCode":"            \"name\": self.name,\n            \"description\": self.description,\n            \"suggested_schedule\": self.suggested_schedule,\n            \"suggested_timezone\": self.suggested_timezone,\n            \"markets\": list(self.markets),\n            \"data_capabilities\": list(self.data_capabilities),\n            \"variables\": dict(self.variables),\n        }\n        if include_body:\n            data[\"body\"] = self.body\n        return data\n\n\ndef _string_list(value: Any, key: str, path: Path) -> Tuple[str, ...]:\n    \"\"\"Coerce a frontmatter value to a tuple of non-empty strings.\"\"\"\n    if isinstance(value, str):\n        value = [value]\n    if not isinstance(value, list) or not value:\n        raise PlaybookError(f\"playbook {path}: {key!r} must be a non-empty list of strings\")\n    items = tuple(str(item).strip() for item in value)\n    if any(not item for item in items):\n        raise PlaybookError(f\"playbook {path}: {key!r} contains an empty entry\")\n    return items\n\n\ndef load_playbook_file(path: Path) -> ResearchPlaybook:\n    \"\"\"Parse one playbook markdown file.\n\n    Args:\n        path: Path to a ``.md`` playbook file.\n\n    Returns:\n        The parsed :class:`ResearchPlaybook`.\n\n    Raises:\n        PlaybookError: If the filename is not a valid slug, the file has no\n            frontmatter, is missing a required key, declares a malformed","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/playbooks.py#L225-L261","documentation":"Raised by _string_list (agent/src/scheduled_research/playbooks.py:243) as PlaybookError when a frontmatter field that must be a non-empty list of strings is neither a string nor a non-empty list. A bare string is coerced to a one-element list; anything else (dict, int, null, empty list) fails with the playbook path and key name in the message.","triggerScenarios":"load_playbook_file on a playbook whose frontmatter has e.g. variables: {} instead of a list, tags: (empty), or tags: 3. YAML flow like 'tags:' with nothing after it parses as None and hits this too.","commonSituations":"Editing playbook markdown frontmatter and leaving a key empty; YAML indentation making an intended list parse as a scalar or dict; copy-pasting frontmatter between playbooks with different field shapes.","solutions":["Fix the frontmatter so the field is a list of strings: tags: [news]","For an optional field, remove the key entirely rather than leaving it empty","Remember a single string is accepted and coerced — wrap multi-value entries in a YAML list","Run load_playbook_file in CI/lint over all playbooks to catch this early"],"exampleFix":"# before (frontmatter)\ntags:\n\n# after\ntags: [news, research]","handlingStrategy":"validation","validationCode":"def string_list_ok(value):\n    if isinstance(value, str):\n        return bool(value.strip())\n    return isinstance(value, list) and len(value) > 0 and all(\n        isinstance(i, str) and i.strip() for i in value\n    )","typeGuard":"from typing import Any, Tuple\n\ndef as_string_list(value: Any) -> Tuple[str, ...]:\n    if isinstance(value, str):\n        value = [value]\n    if not isinstance(value, list) or not value:\n        return ()\n    return tuple(str(i).strip() for i in value if str(i).strip())","tryCatchPattern":"from agent.src.scheduled_research.playbooks import PlaybookError, load_playbook_file\n\ntry:\n    playbook = load_playbook_file(path)\nexcept PlaybookError as exc:\n    if \"must be a non-empty list of strings\" in str(exc):\n        log.warning(\"skipping misconfigured playbook %s: %s\", path, exc)\n        playbook = None\n    else:\n        raise","preventionTips":["Validate all playbook files with load_playbook_file in CI","Delete optional frontmatter keys instead of leaving them empty","Use YAML lists (dash items or [a, b]) for list fields"],"tags":["playbook","frontmatter","yaml","validation"],"backgroundTag":"invalid-frontmatter-configuration","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}