github/spec-kit · error · BundlerError
Each provides.{kind} entry must be a mapping.
Error message
Each provides.{kind} entry must be a mapping. What it means
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.
Source
Thrown at src/specify_cli/bundler/models/manifest.py:261
character-by-character) and any non-list/tuple, matching the manifest
contract (``string[]``).
"""
if raw is None:
return ()
if isinstance(raw, (str, bytes)) or not isinstance(raw, (list, tuple)):
raise BundlerError(f"'{field_name}' must be a list of strings when present.")
return tuple(str(item) for item in raw)
def _parse_refs(kind: str, raw: Any) -> list[ComponentRef]:
if raw is None:
return []
if not isinstance(raw, list):
raise BundlerError(f"provides.{kind} must be a list when present.")
refs: list[ComponentRef] = []
for item in raw:
if not isinstance(item, dict):
raise BundlerError(f"Each provides.{kind} entry must be a mapping.")
priority = _parse_priority(kind, item.get("priority"))
refs.append(
ComponentRef(
kind=kind,
id=_text(item.get("id")),
version=(str(item["version"]).strip() if item.get("version") else None),
source=(str(item["source"]).strip() if item.get("source") else None),
priority=priority,
strategy=(str(item["strategy"]).strip() if item.get("strategy") else None),
)
)
return refs
def _parse_priority(kind: str, raw: Any) -> int | None:
if raw is None:
return None
if isinstance(raw, bool) or not isinstance(raw, (int, str)):View on GitHub (pinned to bf88c9f9a8)
Solutions
- Wrap each entry in a mapping with at least an 'id' key.
- Keep every entry in the list the same mapping shape.
Example fix
# before (bundle.yml)
provides:
skills:
- my-skill
# after
provides:
skills:
- id: my-skill Defensive patterns
Strategy: type-guard
Validate before calling
def provides_entries_are_mappings(data: dict) -> bool:
provides = data.get("provides") or {}
return all(
isinstance(item, dict)
for lst in provides.values()
if isinstance(lst, list)
for item in lst
) Type guard
def is_component_ref(item: object) -> bool:
return isinstance(item, dict) and bool(str(item.get("id", "")).strip()) Try / catch
try:
manifest = BundleManifest.from_file(p)
except BundlerError as e:
if "entry must be a mapping" in str(e):
# rewrite '- my-skill' as '- id: my-skill'
... Prevention
- Component entries are mappings with an 'id' key — bare names are invalid.
- Use one consistent entry shape across a kind list.
When it happens
Trigger: 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.
Common situations: Shorthand single-name lists (natural but unsupported); mixing string IDs and mapping entries in the same list.
Related errors
- provides.{kind} must be a list when present.
- Manifest must be a YAML mapping at the top level.
- Manifest is missing the required 'bundle' mapping.
- 'requires' must be a mapping when present.
- 'integration' must be a mapping when present.
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/bb121ebf20b6dad3.
Report an issue: GitHub.