{"record":{"id":"8704d997412e0d3b","repo":"github/spec-kit","slug":"failed-to-fetch-preset-catalog-from-entry-url","errorCode":null,"errorMessage":"Failed to fetch preset catalog from {entry.url}: {e}","messagePattern":"Failed to fetch preset catalog from (.+?): (.+?)","errorType":"exception","errorClass":"PresetError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/presets/__init__.py","lineNumber":4542,"sourceCode":"                cache_file.write_text(\n                    json.dumps(catalog_data, indent=2), encoding=\"utf-8\"\n                )\n                metadata = {\n                    \"cached_at\": datetime.now(timezone.utc).isoformat(),\n                    \"catalog_url\": entry.url,\n                }\n                metadata_file.write_text(\n                    json.dumps(metadata, indent=2), encoding=\"utf-8\"\n                )\n            except OSError:\n                pass  # Cache is best-effort; proceed with fetched data\n\n            return catalog_data\n\n        except (ImportError, Exception) as e:\n            if isinstance(e, PresetError):\n                raise\n            raise PresetError(\n                f\"Failed to fetch preset catalog from {entry.url}: {e}\"\n            )\n\n    def _get_merged_packs(self, force_refresh: bool = False) -> Dict[str, Dict[str, Any]]:\n        \"\"\"Fetch and merge presets from all active catalogs.\n\n        Higher-priority catalogs (lower priority number) win on ID conflicts.\n\n        Returns:\n            Merged dictionary of pack_id -> pack_data\n        \"\"\"\n        active_catalogs = self.get_active_catalogs()\n        merged: Dict[str, Dict[str, Any]] = {}\n\n        for entry in reversed(active_catalogs):\n            try:\n                data = self._fetch_single_catalog(entry, force_refresh)\n                for pack_id, pack_data in data.get(\"presets\", {}).items():","sourceCodeStart":4524,"sourceCodeEnd":4560,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/presets/__init__.py#L4524-L4560","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check network reachability of the catalog URL (curl -I <url>) and fix proxy/DNS issues","Verify the URL in the catalog config is correct and serves valid JSON under the size limit","If behind a corporate proxy, configure proxy env vars (HTTPS_PROXY) so urllib can connect","If the catalog redirect is rejected, update the config to the final HTTPS URL directly","Retry after transient outages; clear the preset cache to force a clean refetch"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import urllib.request, json\nreq = urllib.request.Request(entry.url, method=\"HEAD\")\nwith urllib.request.urlopen(req, timeout=10) as r:\n    reachable = 200 <= r.status < 400  # preflight before invoking fetch","typeGuard":null,"tryCatchPattern":"from specify_cli.presets import PresetError\nfor attempt in range(3):\n    try:\n        data = manager._fetch_catalog(entry)\n        break\n    except PresetError as e:\n        if attempt == 2 or \"Failed to fetch\" not in str(e):\n            raise\n        time.sleep(2 ** attempt)  # transient network errors only","preventionTips":["Keep catalogs on reliable HTTPS hosts and pin final URLs (avoid redirect chains)","Use cached data when fetch fails instead of hard-failing, if your flow allows","Set proxy env vars in corporate networks so urllib can reach the host"],"tags":["network","http","presets","catalog"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}