github/spec-kit · error · BundlerError

Refusing to download

Error message

Refusing to download {label} over non-HTTPS URL: {url}

What it means

Spec Kit enforces HTTPS for every bundle download URL. Plain HTTP is accepted only for the exact hosts localhost, 127.0.0.1, and ::1; every other scheme and host combination is rejected as BundlerError before network access. Redirect and final response URLs must satisfy the same policy.

Solutions

  1. Serve the artifact over HTTPS and update the catalog download_url to the HTTPS URL.
  2. For a local test server, use exactly `http://localhost`, `http://127.0.0.1`, or `http://[::1]`; `0.0.0.0` and other host names are intentionally rejected.
  3. If a redirect is involved, configure the redirect target to HTTPS so every hop passes the guard.
  4. If you do not control the catalog, install from a local bundle path or choose a catalog source with an HTTPS URL.

Example fix

# before
"download_url": "http://artifacts.internal/my-bundle-1.0.0.zip"

# after
"download_url": "https://artifacts.internal/my-bundle-1.0.0.zip"
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

LOCAL_HOSTS = {"localhost", "127.0.0.1", "::1"}

def is_allowed_download_url(url: str) -> bool:
    try:
        p = urlparse(url)
        host = p.hostname
        _ = p.port
    except ValueError:
        return False
    if not host:
        return False
    return p.scheme == "https" or (p.scheme == "http" and host in LOCAL_HOSTS)

Try / catch

except BundlerError as exc:
    if "non-HTTPS URL" in str(exc):
        report_that_https_or_exact_localhost_is_required()
    else:
        raise

Prevention

When it happens

Trigger: A catalog entry has `ftp://`, `http://`, `git://`, or another non-HTTPS download_url for a non-localhost host, or an HTTPS download redirects to HTTP. The check also runs under --offline before the offline gate.

Common situations: Using an internal Artifactory/Nexus/GitLab server that is configured for HTTP only, testing against `http://0.0.0.0:8000` or an alternate localhost name, or a redirect chain that downgrades to HTTP.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/158f99583dd00529. Report an issue: GitHub.

Appendix: source

Thrown at src/specify_cli/commands/bundle/__init__.py:923

def _require_https(label: str, url: str) -> None:
    from urllib.parse import urlparse

    # urlparse / hostname access raise ValueError on a malformed authority;
    # keep the documented BundlerError contract (older Pythons surface this via
    # the .hostname access below rather than at the urlparse call).
    try:
        parsed = urlparse(url)
        hostname = parsed.hostname
        # Accessing ``port`` performs urllib's syntax/range validation.
        _ = parsed.port
    except ValueError:
        raise BundlerError(
            f"Refusing to download {label}: URL is malformed: {url}"
        ) from None
    is_localhost = hostname in ("localhost", "127.0.0.1", "::1")
    if parsed.scheme != "https" and not (parsed.scheme == "http" and is_localhost):
        raise BundlerError(
            f"Refusing to download {label} over non-HTTPS URL: {url}"
        )
    if not parsed.hostname:
        raise BundlerError(f"Refusing to download {label} from URL with no host: {url}")


def _download_remote_manifest(
    entry_id: str,
    url: str,
    *,
    expected_sha256: str | None = None,
):
    """Fetch a remote bundle artifact over HTTPS and extract its manifest."""
    import io
    import tempfile
    from pathlib import PurePosixPath
    from urllib.parse import urlparse as _urlparse

View on GitHub (pinned to bf88c9f9a8)