github/spec-kit · error · BundlerError
Catalog url must use HTTPS (got {parsed.scheme}://). HTTP is
Error message
Catalog url must use HTTPS (got {parsed.scheme}://). HTTP is only allowed for localhost. What it means
Raised for http/https catalog URLs when the scheme is plain `http` and the hostname is not a loopback address (`localhost`, `127.0.0.1`, `::1`). This mirrors the fetch-time rule from `specify_cli.catalogs._validate_catalog_url` (#3209/#3210) so plaintext HTTP catalogs are caught at config time, not at fetch time.
Source
Thrown at src/specify_cli/bundler/commands_impl/catalog_config.py:177
if not (parsed.scheme or parsed.path):
raise BundlerError(f"Invalid catalog url: '{url}'.")
# Reject unsupported URL schemes (e.g. ssh://, ftp://) up front so they are
# never silently canonicalized as local filesystem paths. Local paths that
# merely contain a ':' but no '://' (e.g. Windows drives) are still allowed.
if "://" in url and parsed.scheme.lower() not in _REMOTE_SCHEMES:
raise BundlerError(
f"Unsupported catalog url scheme '{parsed.scheme}://' in '{url}'. "
"Use http(s)://, file://, builtin://, or a local path."
)
if parsed.scheme.lower() in {"http", "https"}:
# Mirror specify_cli.catalogs._validate_catalog_url (#3209/#3210):
# HTTPS only (HTTP just for localhost), and check hostname, not
# netloc — netloc is truthy for host-less URLs like "https://:8080"
# or "https://user@". Validating here keeps junk out of
# bundle-catalogs.yml instead of failing later at fetch time.
is_localhost = hostname in ("localhost", "127.0.0.1", "::1")
if parsed.scheme.lower() != "https" and not is_localhost:
raise BundlerError(
f"Catalog url must use HTTPS (got {parsed.scheme}://). "
"HTTP is only allowed for localhost."
)
if not hostname:
raise BundlerError(f"Catalog url must be a valid URL with a host: {url}")
url = _canonicalize_url(url)
install_policy = InstallPolicy.parse(policy)
resolved_id = (source_id or _derive_id(url)).strip()
catalogs = _read(project_root)
for existing in catalogs:
if existing.get("id") == resolved_id or existing.get("url") == url:
raise BundlerError(
f"Catalog source '{resolved_id}' (or url) already exists in this project."
)
entry = {View on GitHub (pinned to bf88c9f9a8)
Solutions
- Switch to the https:// version of the URL
- For local development, use `http://localhost...`, `http://127.0.0.1...`, or `http://[::1]...`
- Put an TLS-terminating proxy in front of an internal HTTP mirror
Example fix
# before http://catalog.internal.example.com/catalog.json # after https://catalog.internal.example.com/catalog.json # or for local dev: http://localhost:8080/catalog.json
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
p = urlparse(url)
if p.scheme.lower() in {"http", "https"}:
host = p.hostname
if p.scheme.lower() != "https" and host not in ("localhost", "127.0.0.1", "::1"):
raise SystemExit("non-localhost HTTP catalogs are rejected — use https or localhost") Type guard
def is_https_or_localhost(url: str) -> bool:
p = urlparse(url)
return p.scheme.lower() != "http" or p.hostname in ("localhost", "127.0.0.1", "::1") Try / catch
try:
add_source(project_root, url, policy=policy, priority=50)
except BundlerError as exc:
if "must use HTTPS" in str(exc):
# rewrite http://host -> https://host, or use http://localhost for dev
raise
raise Prevention
- Default to https:// when writing catalog URLs; http only for loopback testing
- For dockerized local catalogs, publish the port on localhost rather than hitting the container IP over http
When it happens
Trigger: `http://catalog.internal.example.com/c.json` — any non-localhost http URL. Note `https://…` never triggers this; only scheme!=https with a non-loopback host does.
Common situations: Internal company mirrors served over plain HTTP; local dev against a non-loopback IP (e.g. docker host `http://172.17.0.1`); stale bookmark of a site that later added TLS.
Related errors
- Catalog entry '{resolved.entry.id}' has a non-HTTP(S) downlo
- 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/537b9b06965ea9c1.
Report an issue: GitHub.