github/spec-kit · error · BundlerError
Catalog entry '{resolved.entry.id}' has a non-HTTP(S) downlo
Error message
Catalog entry '{resolved.entry.id}' has a non-HTTP(S) download_url ({url}); catalog download URLs must be HTTPS (http for localhost) — a file:// URL, a local filesystem path, or a scheme-less value (e.g. 'example.com/bundle.zip') is not accepted. To install a bundle from disk, pass the path directly: 'specify bundle install <path-to-bundle.yml | bundle-dir | .zip>'. What it means
The download_url scheme check in _download_manifest: catalog URLs must be HTTPS (plain http only for localhost). This fires for scheme-less values ('example.com/bundle.zip'), file:// URLs, bare filesystem paths, and Windows drive paths ('C:\bundle.yml' — urlparse sees a single-letter scheme), each rejected with a redirect telling the user how to install from disk instead. The check runs before the offline gate so the real problem is reported in every mode.
Source
Thrown at src/specify_cli/commands/bundle/__init__.py:876
# makes urlparse raise ValueError. Surface it as the documented
# BundlerError, like the sibling ``_validate_remote_url``, rather than
# leaking a raw ValueError past the callers, which only catch BundlerError.
try:
parsed = urlparse(url)
except ValueError:
raise BundlerError(
f"Catalog entry '{resolved.entry.id}' has a malformed download_url: {url}"
) from None
scheme = parsed.scheme.lower()
# ``file://`` URLs and bare filesystem paths (including Windows drive paths
# like ``C:\bundle.yml``, which urlparse reads as a single-letter scheme)
# are not valid catalog download URLs. Catalog URLs are HTTPS-only across
# every catalog system; installing from disk is done by passing the path
# positionally, which never reaches URL resolution. Give an actionable
# error rather than accepting a scheme the rest of the codebase rejects.
if scheme in ("", "file") or re.match(r"^[A-Za-z]:[\\/]", url):
raise BundlerError(
f"Catalog entry '{resolved.entry.id}' has a non-HTTP(S) download_url "
f"({url}); catalog download URLs must be HTTPS (http for localhost) — "
"a file:// URL, a local filesystem path, or a scheme-less value "
"(e.g. 'example.com/bundle.zip') is not accepted. "
"To install a bundle from disk, pass the path directly: "
"'specify bundle install <path-to-bundle.yml | bundle-dir | .zip>'."
)
# Validate the scheme/host *before* the offline gate so an invalid or
# non-HTTPS download_url reports the real problem in every mode, rather
# than a misleading "Network access disabled" under --offline.
# (_download_remote_manifest re-checks this, but only once network access
# is permitted.) HTTPS-only, http allowed for localhost.
_require_https(f"bundle '{resolved.entry.id}'", url)
if offline:
raise BundlerError(
f"Network access disabled; cannot download bundle '{resolved.entry.id}' "View on GitHub (pinned to bf88c9f9a8)
Solutions
- Host the artifact over HTTPS and set download_url to the https:// URL.
- To install from local disk, do not fix the catalog — pass the path positionally: specify bundle install <path-to-bundle.yml | bundle-dir | .zip>.
- For local HTTP testing, use http://localhost/... which the localhost exception permits.
Example fix
# before (catalog entry) "download_url": "file:///srv/bundles/my-bundle.zip" # after "download_url": "https://bundles.example.com/my-bundle.zip"
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
import re
url = resolved.entry.download_url
parsed = urlparse(url)
scheme = parsed.scheme.lower()
if scheme in ("", "file") or re.match(r"^[A-Za-z]:[\\/]", url):
raise SystemExit("Catalog download_url must be https:// (http for localhost); use a path argument for disk installs") Type guard
def is_https_catalog_url(url: str) -> bool:
from urllib.parse import urlparse
import re
if re.match(r"^[A-Za-z]:[\\/]", url):
return False
scheme = urlparse(url).scheme.lower()
return scheme == "https" or (scheme == "http" and "localhost" in urlparse(url).netloc) Try / catch
try:
manifest = _download_manifest(resolved, offline=offline)
except BundlerError as exc:
if "non-HTTP(S) download_url" in str(exc):
# host the artifact over HTTPS, or install locally via positional path
... Prevention
- Never put file:// paths or bare filesystem paths in catalog download_url fields.
- Host bundle artifacts on an HTTPS endpoint before indexing them.
When it happens
Trigger: A catalog entry whose download_url is 'file:///bundles/my-bundle.zip', '/home/me/bundle.zip', 'C:\bundles\bundle.zip', or 'example.com/bundle.zip'; any 'specify bundle install <catalog-id>' resolving to that entry.
Common situations: Private/internal catalogs written with LAN file shares; Windows-path entries; users copying a path into the catalog instead of hosting the artifact over HTTPS.
Related errors
- Catalog url must use HTTPS (got {parsed.scheme}://). HTTP is
- Refusing to download {label} over non-HTTPS URL: {url}
- Invalid catalog url: '{url}'.
- Unsupported catalog url scheme '{parsed.scheme}://' in '{url
- Catalog url must be a valid URL with a host: {url}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/91a9795a41246983.
Report an issue: GitHub.