github/spec-kit · error · PresetError

Failed to fetch preset catalog from {entry.url}: {e}

Error message

Failed to fetch preset catalog from {entry.url}: {e}

What it means

Fetching a preset catalog over HTTP failed. The per-catalog fetch (redirect-validated open, size-limited read, JSON parse, payload validation) wraps any non-PresetError exception — URLError, timeout, JSONDecodeError, ImportError — into PresetError; existing PresetErrors (e.g. payload validation failures) are re-raised unchanged.

Source

Thrown at src/specify_cli/presets/__init__.py:4542

                cache_file.write_text(
                    json.dumps(catalog_data, indent=2), encoding="utf-8"
                )
                metadata = {
                    "cached_at": datetime.now(timezone.utc).isoformat(),
                    "catalog_url": entry.url,
                }
                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 (ImportError, Exception) as e:
            if isinstance(e, PresetError):
                raise
            raise PresetError(
                f"Failed to fetch preset catalog from {entry.url}: {e}"
            )

    def _get_merged_packs(self, force_refresh: bool = False) -> Dict[str, Dict[str, Any]]:
        """Fetch and merge presets from all active catalogs.

        Higher-priority catalogs (lower priority number) win on ID conflicts.

        Returns:
            Merged dictionary of pack_id -> pack_data
        """
        active_catalogs = self.get_active_catalogs()
        merged: Dict[str, Dict[str, Any]] = {}

        for entry in reversed(active_catalogs):
            try:
                data = self._fetch_single_catalog(entry, force_refresh)
                for pack_id, pack_data in data.get("presets", {}).items():

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Check network reachability of the catalog URL (curl -I <url>) and fix proxy/DNS issues
  2. Verify the URL in the catalog config is correct and serves valid JSON under the size limit
  3. If behind a corporate proxy, configure proxy env vars (HTTPS_PROXY) so urllib can connect
  4. If the catalog redirect is rejected, update the config to the final HTTPS URL directly
  5. Retry after transient outages; clear the preset cache to force a clean refetch
Defensive patterns

Strategy: retry

Validate before calling

import urllib.request, json
req = urllib.request.Request(entry.url, method="HEAD")
with urllib.request.urlopen(req, timeout=10) as r:
    reachable = 200 <= r.status < 400  # preflight before invoking fetch

Try / catch

from specify_cli.presets import PresetError
for attempt in range(3):
    try:
        data = manager._fetch_catalog(entry)
        break
    except PresetError as e:
        if attempt == 2 or "Failed to fetch" not in str(e):
            raise
        time.sleep(2 ** attempt)  # transient network errors only

Prevention

When it happens

Trigger: Calling _fetch_catalog(entry) when the catalog URL is unreachable (DNS failure, connection refused, timeout after 10s), returns invalid JSON or an oversized body (>MAX_JSON_CATALOG_BYTES), redirects to a URL that fails _validate_catalog_url, or when a required import is missing.

Common situations: Offline machine or corporate proxy blocking the catalog host; catalog server down or returning an HTML error page; typo'd catalog URL in config; redirect to HTTP or disallowed host being rejected by the security validator.

Related errors


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