{"record":{"id":"6c617967a92610e8","repo":"github/spec-kit","slug":"failed-to-download-bundle-entry-id-from-sour","errorCode":null,"errorMessage":"Failed to download bundle '{entry_id}' from {_source_desc}: {exc}","messagePattern":"Failed to download bundle '(.+?)' from (.+?): (.+?)","errorType":"exception","errorClass":"BundlerError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/commands/bundle/__init__.py","lineNumber":1002,"sourceCode":"            _require_https(f\"bundle '{entry_id}'\", resp.geturl())\n            raw = read_response_limited(\n                resp,\n                max_bytes=MAX_DOWNLOAD_BYTES,\n                error_type=BundlerError,\n                label=f\"bundle '{entry_id}' download\",\n            )\n        verify_archive_sha256(\n            raw,\n            expected_sha256,\n            entry_id,\n            BundlerError,\n        )\n    except BundlerError:\n        raise\n    except Exception as exc:  # noqa: BLE001\n        # Report the original catalog URL so users know which entry to fix,\n        # and include the resolved URL when it differs for easier debugging.\n        raise BundlerError(\n            f\"Failed to download bundle '{entry_id}' from {_source_desc}: {exc}\"\n        ) from exc\n\n    # A .zip artifact is written to a temp file and parsed via the local-source\n    # path (which extracts bundle.yml); any other payload is treated as YAML.\n    # Detection uses the path component of the original catalog URL (via\n    # PurePosixPath so query strings and fragments are ignored, and URL paths\n    # are always treated as POSIX regardless of host OS), falling back to the\n    # module-level _ZIP_SIGNATURES magic-byte check for direct REST API asset\n    # URLs which carry no file extension.\n    _url_ext = PurePosixPath(_urlparse(url).path).suffix.lower()\n    try:\n        if _url_ext == \".zip\" or raw[:4] in _ZIP_SIGNATURES:\n            with tempfile.TemporaryDirectory() as tmp:\n                artifact = Path(tmp) / \"bundle.zip\"\n                artifact.write_bytes(raw)\n                # Wrap ZIP parsing so any failure (BadZipFile, missing\n                # bundle.yml, etc.) references the source URL rather than the","sourceCodeStart":984,"sourceCodeEnd":1020,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/commands/bundle/__init__.py#L984-L1020","documentation":"This BundlerError wraps any unexpected exception raised while opening the authenticated download URL, reading the bounded response, or verifying the artifact checksum. The message reports the original catalog URL and, when different, the resolved GitHub API URL, with the underlying exception chained as __cause__.","triggerScenarios":"`specify bundle info/install/update` reaches _download_remote_manifest and open_url raises a URLError/HTTPError, the connection times out, TLS fails, the response exceeds MAX_DOWNLOAD_BYTES through a non-BundlerError path, or another transport-level exception escapes.","commonSituations":"No network connectivity, a 404 after a release asset was deleted, an inaccessible private repository, a corporate proxy, a slow mirror that times out, or a host that serves an error page.","solutions":["Open the URL shown in the message in a browser or with curl to check for 404, authentication, TLS, and proxy errors.","Restore network/proxy access or retry once the endpoint is reachable.","For a private GitHub artifact, ensure the configured GitHub authentication can access the repository/release.","Verify that the catalog still points to an existing release asset and that the published artifact is within the download size limit.","Run with debug output or inspect `exc.__cause__` in a calling program if the text does not identify the transport failure."],"exampleFix":"# catalog.json (before)\n\"download_url\": \"https://github.com/org/repo/releases/download/v1.0/missing-bundle.zip\"\n\n# catalog.json (after)\n\"download_url\": \"https://github.com/org/repo/releases/download/v1.0.0/my-bundle.zip\"","handlingStrategy":"try-catch","validationCode":"from urllib.parse import urlparse\n\ndef download_url_is_preflightable(url: str) -> bool:\n    try:\n        p = urlparse(url)\n    except ValueError:\n        return False\n    return p.scheme == \"https\" and bool(p.hostname)","typeGuard":null,"tryCatchPattern":"try:\n    specify_bundle_install(bundle_id)\nexcept BundlerError as exc:\n    cause = exc.__cause__\n    if \"Failed to download bundle\" not in str(exc):\n        raise\n    if isinstance(cause, (TimeoutError, ConnectionError)):\n        schedule_retry(bundle_id)\n    else:\n        surface_download_failure(url, cause or exc)","preventionTips":["Verify release asset URLs with an authenticated HEAD/GET before publishing catalog entries.","Keep artifacts within Spec Kit's maximum download size and publish stable release URLs.","Monitor private repository permissions when catalogs reference private assets."],"tags":["network","download","https","bundle","catalog"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}