github/spec-kit · error · ExtensionError

Invalid catalog format from {url}

Error message

Invalid catalog format from {url}

What it means

Second stage of catalog validation: the payload is a JSON object but is missing either the schema_version or the extensions key (or both). Both keys are mandatory for a spec-kit extension catalog, so an object lacking them is rejected as an invalid catalog format.

Source

Thrown at src/specify_cli/extensions/__init__.py:3694

        object and the nested mapping (see ``integrations/catalog.py``);
        the extension catalog must stay consistent so a malformed payload
        surfaces as the user-facing ``Invalid catalog format`` error
        instead of a raw Python traceback.

        Args:
            catalog_data: Parsed JSON payload from the catalog source.
            url: Source URL — used in the error message so the user can
                tell which catalog in a multi-catalog stack is malformed.

        Raises:
            ExtensionError: If the payload's shape is invalid.
        """
        if not isinstance(catalog_data, dict):
            raise ExtensionError(
                f"Invalid catalog format from {url}: expected a JSON object"
            )
        if "schema_version" not in catalog_data or "extensions" not in catalog_data:
            raise ExtensionError(f"Invalid catalog format from {url}")
        if not isinstance(catalog_data.get("extensions"), dict):
            raise ExtensionError(
                f"Invalid catalog format from {url}: 'extensions' must be a JSON object"
            )

    def get_active_catalogs(self) -> List[CatalogEntry]:
        """Get the ordered list of active catalogs.

        Resolution order:
        1. SPECKIT_CATALOG_URL env var — single catalog replacing all defaults
        2. Project-level .specify/extension-catalogs.yml
        3. User-level ~/.specify/extension-catalogs.yml
        4. Built-in default stack (default + community)

        Returns:
            List of CatalogEntry objects sorted by priority (ascending)

        Raises:

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Add both required keys to the catalog document: schema_version (e.g. 1) and extensions (object keyed by extension id)
  2. Check for key typos — plural 'extensions' and exact 'schema_version' are required
  3. Validate locally before publishing: `python -c "import json;d=json.load(open('catalog.json'));assert {'schema_version','extensions'} <= d.keys()"`
  4. If you don't control the URL, remove it from the catalog config and rely on the built-in default+community stack

Example fix

# before
{
  "extensions": { "my-ext": {"name": "My Ext"} }
}

# after
{
  "schema_version": 1,
  "extensions": { "my-ext": {"name": "My Ext"} }
}
Defensive patterns

Strategy: validation

Validate before calling

REQUIRED_CATALOG_KEYS = {'schema_version', 'extensions'}

def catalog_has_required_keys(data: dict) -> bool:
    return REQUIRED_CATALOG_KEYS <= data.keys()

Type guard

def is_catalog_shaped(data: object) -> bool:
    return (
        isinstance(data, dict)
        and 'schema_version' in data
        and 'extensions' in data
        and isinstance(data['extensions'], dict)
    )

Prevention

When it happens

Trigger: A catalog URL returning `{"data": ...}` or an extensions-only object without schema_version; any object payload where 'schema_version' not in catalog_data or 'extensions' not in catalog_data evaluates true.

Common situations: Hand-authoring a catalog and omitting schema_version; server returning a generic API envelope ({'status':'ok',...}); typos like extension/version singular forms.

Related errors


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