{"record":{"id":"39bce044a4d9dcb4","repo":"github/spec-kit","slug":"failed-to-download-preset-from-download-url-e","errorCode":null,"errorMessage":"Failed to download preset from {download_url}: {e}","messagePattern":"Failed to download preset from (.+?): (.+?)","errorType":"exception","errorClass":"PresetError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/presets/__init__.py","lineNumber":4955,"sourceCode":"                    else original_download_url\n                ),\n                content_type=content_type,\n                error_type=PresetError,\n            )\n            archive_path = build_safe_download_path(\n                target_dir,\n                pack_id,\n                version,\n                error_type=PresetError,\n                label=\"preset\",\n                suffix=archive_suffix(archive_format),\n            )\n            os.replace(staging_path, archive_path)\n            staging_path = None\n            return archive_path\n\n        except urllib.error.URLError as e:\n            raise PresetError(\n                f\"Failed to download preset from {download_url}: {e}\"\n            )\n        except IOError as e:\n            raise PresetError(f\"Failed to save preset archive: {e}\")\n        finally:\n            if staging_path is not None:\n                staging_path.unlink(missing_ok=True)\n\n    def clear_cache(self):\n        \"\"\"Clear all catalog cache files, including per-URL hashed caches.\"\"\"\n        if self.cache_dir.exists():\n            for f in self.cache_dir.iterdir():\n                if f.is_file() and f.name.startswith(\"catalog\"):\n                    f.unlink(missing_ok=True)\n\n\nclass PresetResolver:\n    \"\"\"Resolves template names to file paths using a priority stack.","sourceCodeStart":4937,"sourceCodeEnd":4973,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/presets/__init__.py#L4937-L4973","documentation":"The archive download failed at the HTTP/URL layer: urllib.error.URLError (and its HTTPError subclass) raised while opening or reading the download stream. It is wrapped into PresetError with the source URL; note URLError is a subclass of OSError, but it is caught before the IOError branch.","triggerScenarios":"download_preset_archive when the download host is unreachable, the connection times out, TLS fails, or the server returns 4xx/5xx (HTTPError) — after all URL validations passed.","commonSituations":"Catalog reachable but artifact host (CDN, release bucket) down or moved; 404 because the versioned archive was deleted/renamed; proxy/firewall blocking the download domain; expired token in a signed URL.","solutions":["Fetch the URL manually (curl -fSL <download_url>) to see the concrete HTTP/network error","If 404/410, refresh the catalog so download_url points at the current artifact, or pin a version that still exists","Fix proxy/certificate environment issues (HTTPS_PROXY, CA bundle) for the artifact host","Retry after transient failures — the download is not cached until it fully succeeds (staging file is unlinked in finally)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import urllib.request\nreq = urllib.request.Request(download_url, method=\"HEAD\")\ntry:\n    with urllib.request.urlopen(req, timeout=10) as r:\n        downloadable = 200 <= r.status < 400\nexcept OSError:\n    downloadable = False  # preflight before the real download","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        archive = manager.download_preset_archive(pack_id)\n        break\n    except PresetError as e:\n        if attempt == 2 or \"Failed to download\" not in str(e):\n            raise\n        time.sleep(2 ** attempt)  # transient URLError/HTTPError only","preventionTips":["Keep versioned artifacts online — do not delete old release archives still referenced by catalogs","Monitor artifact hosts (CDN/bucket) availability","Distinguish network errors (retryable) from validation errors (not retryable) by message"],"tags":["network","http","presets","download"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}