github/spec-kit · error · PresetError

Failed to fetch preset catalog from {catalog_url}: {e}

Error message

Failed to fetch preset catalog from {catalog_url}: {e}

What it means

Same failure class as the per-entry fetch, but on the URL-keyed single-catalog fetch path (used by search/list flows): any non-PresetError exception during download, size-limited read, JSON parse, payload validation, or caching of catalog_url is wrapped into PresetError; PresetErrors pass through unchanged.

Source

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

                    json.dumps(catalog_data, indent=2), encoding="utf-8"
                )

                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 (ImportError, Exception) as e:
            if isinstance(e, PresetError):
                raise
            raise PresetError(
                f"Failed to fetch preset catalog from {catalog_url}: {e}"
            )

    def search(
        self,
        query: Optional[str] = None,
        tag: Optional[str] = None,
        author: Optional[str] = None,
    ) -> List[Dict[str, Any]]:
        """Search catalog for presets.

        Searches across all active catalogs (merged by priority) so that
        community and custom catalogs are included in results.

        Args:
            query: Search query (searches name, description, tags)
            tag: Filter by specific tag
            author: Filter by author name

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Verify the catalog URL responds with valid JSON: curl -sSL <url> | python -m json.tool
  2. Fix connectivity (network, proxy env vars, certificates) before running preset search
  3. If a redirect target is rejected, pin the config to the final HTTPS URL
  4. Clear the preset cache directory and retry to rule out cache corruption
Defensive patterns

Strategy: retry

Validate before calling

import urllib.request
try:
    urllib.request.urlopen(catalog_url, timeout=10).close()
    ok = True
except OSError:
    ok = False  # skip/defer search when offline

Try / catch

try:
    results = manager.search(query)
except PresetError as e:
    if "Failed to fetch preset catalog" in str(e):
        results = cached_results or []   # degrade gracefully offline
    else:
        raise

Prevention

When it happens

Trigger: Calling search()/list flows that fetch a catalog by URL when the request fails (URLError, timeout), the response is not valid JSON, exceeds MAX_JSON_CATALOG_BYTES, fails payload validation, or the URL fails validation after redirects.

Common situations: Running preset search on a machine with no/blocked internet; catalog host serving a truncated or oversized payload; stale cached metadata forcing refetch during an outage; SSL interception breaking the TLS handshake.

Related errors


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