github/spec-kit · error · ExtensionError

Invalid JSON in catalog: {e}

Error message

Invalid JSON in catalog: {e}

What it means

Companion to the URLError case on the single-catalog path: the HTTP fetch succeeded but json parsing of the response body raised JSONDecodeError, so the catalog is declared invalid JSON with the parse error included.

Source

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

                )

                # Save cache metadata
                metadata = {
                    "cached_at": datetime.now(timezone.utc).isoformat(),
                    "catalog_url": catalog_url,
                }
                self.cache_metadata_file.write_text(
                    json.dumps(metadata, indent=2), encoding="utf-8"
                )
            except OSError:
                pass  # Cache is best-effort; proceed with fetched data

            return catalog_data

        except urllib.error.URLError as e:
            raise ExtensionError(f"Failed to fetch catalog from {catalog_url}: {e}")
        except json.JSONDecodeError as e:
            raise ExtensionError(f"Invalid JSON in catalog: {e}")

    def search(
        self,
        query: Optional[str] = None,
        tag: Optional[str] = None,
        author: Optional[str] = None,
        verified_only: bool = False,
    ) -> List[Dict[str, Any]]:
        """Search catalog for extensions across all active catalogs.

        Args:
            query: Search query (searches name, description, tags)
            tag: Filter by specific tag
            author: Filter by author name
            verified_only: If True, show only verified extensions

        Returns:
            List of matching extension metadata, each annotated with

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Inspect the actual body: `curl -s <catalog_url> | head -c 400`
  2. Use the raw JSON endpoint rather than a UI/auth-wrapped page
  3. Fix credentials or headers the catalog server requires so it serves JSON
  4. Re-validate and re-upload edited catalog files after `python -m json.tool` passes
Defensive patterns

Strategy: validation

Validate before calling

import json, urllib.request

def probe_catalog_json(url: str) -> bool:
    with urllib.request.urlopen(url, timeout=10) as r:
        head = r.read(1)
        if not head:
            return False
        r2 = urllib.request.urlopen(url, timeout=10)
        try:
            json.loads(r2.read())
            return True
        except json.JSONDecodeError:
            return False

Try / catch

from specify_cli.extensions import ExtensionError

try:
    results = catalog.search(query='ci')
except ExtensionError as e:
    if 'Invalid JSON in catalog' in str(e):
        # body wasn't JSON: inspect with curl, fix auth/raw-URL, then retry

Prevention

When it happens

Trigger: catalog_url returns non-JSON bytes: an HTML error/login page with 200 status, an empty body, truncated output from a flaky proxy, or JSON with a syntax error.

Common situations: Auth-protected catalog returning an HTML login page; object-storage URL serving an XML error document; hand-edited catalog uploaded with a trailing comma; CDN serving a partial response on timeout.

Understand the failure class

Related errors


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