github/spec-kit · error · BundlerError
'provides' must be a mapping when present.
Error message
'provides' must be a mapping when present.
What it means
Raised by BundleManifest.from_dict when an optional 'provides' key is present but is not a YAML mapping. 'provides' groups component lists (skills, commands, templates, ...) keyed by kind; a null/absent value defaults to empty, but any non-mapping type is malformed and rejected.
Source
Thrown at src/specify_cli/bundler/models/manifest.py:139
tools=_parse_str_list(requires_raw.get("tools"), "requires.tools"),
mcp=_parse_str_list(requires_raw.get("mcp"), "requires.mcp"),
)
integration = None
integration_raw = data.get("integration")
# Mirror the requires/provides guards above: a present-but-non-mapping
# 'integration' (e.g. a bare string "copilot") was silently dropped,
# leaving the bundle wrongly integration-agnostic. Reject it instead.
if integration_raw is not None and not isinstance(integration_raw, dict):
raise BundlerError("'integration' must be a mapping when present.")
if isinstance(integration_raw, dict) and integration_raw.get("id"):
integration = IntegrationRef(id=str(integration_raw["id"]).strip())
provides = data.get("provides")
if provides is None:
provides = {}
elif not isinstance(provides, dict):
raise BundlerError("'provides' must be a mapping when present.")
tags_raw = data.get("tags")
if tags_raw is None:
tags_raw = []
else:
tags_raw = _parse_str_list(tags_raw, "tags")
manifest = cls(
schema_version=schema_version,
bundle=meta,
requires=requires,
integration=integration,
extensions=_parse_refs("extensions", provides.get("extensions")),
presets=_parse_refs("presets", provides.get("presets")),
steps=_parse_refs("steps", provides.get("steps")),
workflows=_parse_refs("workflows", provides.get("workflows")),
tags=tuple(str(t) for t in tags_raw),
)View on GitHub (pinned to bf88c9f9a8)
Solutions
- Nest component lists under kind keys inside a 'provides' mapping.
- Remove 'provides' if the bundle provides nothing — absence is valid.
Example fix
# before (bundle.yml)
provides:
- id: my-skill
kind: skill
# after
provides:
skills:
- id: my-skill Defensive patterns
Strategy: type-guard
Validate before calling
def provides_shape_ok(data: dict) -> bool:
p = data.get("provides")
return p is None or isinstance(p, dict) Type guard
def is_provides_mapping(raw: object) -> bool:
return raw is None or isinstance(raw, dict) Try / catch
try:
manifest = BundleManifest.from_file(p)
except BundlerError as e:
if "'provides' must be a mapping" in str(e):
# restructure to kind-keyed lists under a mapping
... Prevention
- 'provides' maps component kinds to lists; it is never a flat list itself.
- Mirror the shape: provides: {skills: [...], commands: [...]}.
When it happens
Trigger: A manifest contains 'provides:' followed by a list (e.g. a flat list of component entries) or a scalar. Parsing it with BundleManifest.from_dict raises before component-ref parsing begins.
Common situations: Flattening provides into a list because the kinds feel redundant; hand-writing a first manifest; copy-paste from the 'requires' block's list style.
Related errors
- 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.
- '{field_name}' must be a list of strings when present.
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/0b5eeda03262aa4e.
Report an issue: GitHub.