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] = entry

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Add a 'bundles' object mapping bundle ids to entry objects.
  2. If the catalog uses a newer format, update specify/spec-kit to a version that supports it.
  3. Verify with curl/jq that .bundles is an object before wiring the source in.
  4. 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

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


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/954d5523d73d4dec. Report an issue: GitHub.