github/spec-kit · error · BundlerError
Catalog payload is missing a 'bundles' object.
Error message
Catalog payload is missing a 'bundles' object.
What it means
Raised by load_catalog_payload() when the top-level object is present but its 'bundles' value is missing or not a dict. 'bundles' is the mandatory map of bundle-id to entry object; null, a list, or a string in that slot raises this error.
Source
Thrown at src/specify_cli/bundler/models/catalog.py:220
return CatalogEntry(
id=self.id, name=self.name, version=self.version, role=self.role,
description=self.description, author=self.author, license=self.license,
download_url=self.download_url,
requires_speckit_version=self.requires_speckit_version,
sha256=self.sha256,
provides=self.provides, repository=self.repository, tags=self.tags,
verified=self.verified, source_id=source.id,
source_policy=source.install_policy,
)
def load_catalog_payload(data: Any) -> dict[str, CatalogEntry]:
"""Parse a catalog JSON payload into ``{bundle_id: CatalogEntry}``."""
if not isinstance(data, dict):
raise BundlerError("Catalog payload must be a JSON object.")
bundles_raw = data.get("bundles")
if not isinstance(bundles_raw, dict):
raise BundlerError("Catalog payload is missing a 'bundles' object.")
entries: dict[str, CatalogEntry] = {}
for bundle_id, entry_raw in bundles_raw.items():
key = str(bundle_id)
entry = CatalogEntry.from_dict(entry_raw)
# The enclosing key is the authoritative bundle id used by
# search/resolve/install. Reject entries whose own ``id`` is missing or
# disagrees with the key, so a malformed or malicious catalog can't list
# an id that resolves to a different (or no) bundle.
if not entry.id:
raise BundlerError(
f"Catalog entry for '{key}' is missing its 'id' field."
)
if entry.id != key:
raise BundlerError(
f"Catalog entry id mismatch: key '{key}' != entry id "
f"'{entry.id}'."
)
entries[key] = entryView on GitHub (pinned to bf88c9f9a8)
Solutions
- Add a 'bundles' object mapping bundle ids to entry objects.
- If the catalog uses a newer format, update specify/spec-kit to a version that supports it.
- Verify with curl/jq that .bundles is an object before wiring the source in.
- Remove or replace catalog sources that persistently serve bundle-less payloads.
Example fix
# before (catalog JSON)
{"metadata": {"generated": "2026-01-01"}}
# after (catalog JSON)
{"bundles": {"my-bundle": {"id": "my-bundle", ...}}} Defensive patterns
Strategy: validation
Validate before calling
bundles = data.get("bundles") if isinstance(data, dict) else None
if not isinstance(bundles, dict):
raise ValueError("catalog payload missing a 'bundles' object")
load_catalog_payload(data) Type guard
def has_bundles_object(data: object) -> bool:
return isinstance(data, dict) and isinstance(data.get("bundles"), dict) Try / catch
try:
load_catalog_payload(data)
except BundlerError as e:
if "'bundles' object" in str(e):
skip_source_with_schema_warning(source) Prevention
- Check .bundles exists and is an object (jq '.bundles | type') before adding a source.
- Pin to catalog format versions your specify release supports.
- Alert catalog maintainers when their format changes break consumers.
When it happens
Trigger: A catalog object like {"version": 2} with no 'bundles' key; "bundles": [...] (array); "bundles": null; schema renamed in a newer catalog format.
Common situations: Version mismatch between catalog format generations; partial or truncated catalogs; hand-authored catalogs omitting the wrapper; upstream API change at a catalog host.
Related errors
- A catalog source is missing its 'id'.
- Catalog source '{source_id}' is missing its 'url'.
- Catalog source '{source_id}' is missing its 'priority'.
- Catalog payload must be a JSON object.
- Malformed catalog config at {path}: expected a mapping at th
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/954d5523d73d4dec.
Report an issue: GitHub.