{"record":{"id":"bb121ebf20b6dad3","repo":"github/spec-kit","slug":"each-provides-kind-entry-must-be-a-mapping","errorCode":null,"errorMessage":"Each provides.{kind} entry must be a mapping.","messagePattern":"Each provides\\.(.+?) entry must be a mapping\\.","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/bundler/models/manifest.py","lineNumber":261,"sourceCode":"    character-by-character) and any non-list/tuple, matching the manifest\n    contract (``string[]``).\n    \"\"\"\n    if raw is None:\n        return ()\n    if isinstance(raw, (str, bytes)) or not isinstance(raw, (list, tuple)):\n        raise BundlerError(f\"'{field_name}' must be a list of strings when present.\")\n    return tuple(str(item) for item in raw)\n\n\ndef _parse_refs(kind: str, raw: Any) -> list[ComponentRef]:\n    if raw is None:\n        return []\n    if not isinstance(raw, list):\n        raise BundlerError(f\"provides.{kind} must be a list when present.\")\n    refs: list[ComponentRef] = []\n    for item in raw:\n        if not isinstance(item, dict):\n            raise BundlerError(f\"Each provides.{kind} entry must be a mapping.\")\n        priority = _parse_priority(kind, item.get(\"priority\"))\n        refs.append(\n            ComponentRef(\n                kind=kind,\n                id=_text(item.get(\"id\")),\n                version=(str(item[\"version\"]).strip() if item.get(\"version\") else None),\n                source=(str(item[\"source\"]).strip() if item.get(\"source\") else None),\n                priority=priority,\n                strategy=(str(item[\"strategy\"]).strip() if item.get(\"strategy\") else None),\n            )\n        )\n    return refs\n\n\ndef _parse_priority(kind: str, raw: Any) -> int | None:\n    if raw is None:\n        return None\n    if isinstance(raw, bool) or not isinstance(raw, (int, str)):","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/bundler/models/manifest.py#L243-L279","documentation":"Raised by the manifest helper _parse_refs when an entry inside a 'provides.<kind>' list is not a YAML mapping. Each entry must be a mapping carrying id, and optionally version, source, priority, and strategy — the component-ref contract.","triggerScenarios":"A provides list contains a bare string entry, e.g. 'provides: {skills: [my-skill]}', or a nested list. _parse_refs iterates and rejects the first non-dict item.","commonSituations":"Shorthand single-name lists (natural but unsupported); mixing string IDs and mapping entries in the same list.","solutions":["Wrap each entry in a mapping with at least an 'id' key.","Keep every entry in the list the same mapping shape."],"exampleFix":"# before (bundle.yml)\nprovides:\n  skills:\n    - my-skill\n\n# after\nprovides:\n  skills:\n    - id: my-skill","handlingStrategy":"type-guard","validationCode":"def provides_entries_are_mappings(data: dict) -> bool:\n    provides = data.get(\"provides\") or {}\n    return all(\n        isinstance(item, dict)\n        for lst in provides.values()\n        if isinstance(lst, list)\n        for item in lst\n    )","typeGuard":"def is_component_ref(item: object) -> bool:\n    return isinstance(item, dict) and bool(str(item.get(\"id\", \"\")).strip())","tryCatchPattern":"try:\n    manifest = BundleManifest.from_file(p)\nexcept BundlerError as e:\n    if \"entry must be a mapping\" in str(e):\n        # rewrite '- my-skill' as '- id: my-skill'\n        ...","preventionTips":["Component entries are mappings with an 'id' key — bare names are invalid.","Use one consistent entry shape across a kind list."],"tags":["bundler","manifest","yaml","validation","provides"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}