github/spec-kit · error · BundlerError
provides.{kind} must be a list when present.
Error message
provides.{kind} must be a list when present. What it means
Raised by the manifest helper _parse_refs when a 'provides.<kind>' entry (e.g. provides.skills) is present but is not a YAML list. Each kind under 'provides' must be a list of component mappings; a null/absent kind yields no refs, but a scalar or mapping is malformed.
Source
Thrown at src/specify_cli/bundler/models/manifest.py:257
def _parse_str_list(raw: Any, field_name: str) -> tuple[str, ...]:
"""Coerce a manifest list-of-strings field into a tuple of strings.
Rejects a bare string/bytes (which would otherwise be iterated
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
View on GitHub (pinned to bf88c9f9a8)
Solutions
- Make each provides.<kind> value a list of component mappings.
- Remove the kind key if that kind provides nothing.
Example fix
# before (bundle.yml)
provides:
skills:
id: my-skill
# after
provides:
skills:
- id: my-skill Defensive patterns
Strategy: validation
Validate before calling
def provides_kind_lists_ok(data: dict) -> bool:
provides = data.get("provides") or {}
return all(v is None or isinstance(v, list) for v in provides.values()) Type guard
def is_component_ref_list(raw: object) -> bool:
return raw is None or (isinstance(raw, list) and all(isinstance(i, dict) for i in raw)) Try / catch
try:
manifest = BundleManifest.from_file(p)
except BundlerError as e:
if "must be a list when present" in str(e):
# wrap the single mapping entry in a list
... Prevention
- Each provides.<kind> is a list, even with one component.
- Keep the outer mapping / inner list distinction straight when authoring.
When it happens
Trigger: A manifest contains 'provides: {skills: {id: my-skill}}' (a single mapping) or 'provides: {skills: my-skill}' (a scalar); _parse_refs(kind, raw) rejects the non-list before iterating entries.
Common situations: Providing a single component and omitting the '-' bullet; mixing up the per-kind list shape with the outer 'provides' mapping shape.
Related errors
- Each provides.{kind} entry must be a mapping.
- 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/31c449b9c44e6f13.
Report an issue: GitHub.