jdx/mise · error

unsupported relay host

Error message

unsupported relay host

What it means

After passing the scheme/port/credential checks, request() maps the URL host to a relay path prefix: api.github.com maps to /api and github.com maps to /web. Any other host — including GitHub Enterprise, mirrors, or typos — has no mapping and is rejected with "unsupported relay host". The relay can only proxy the two canonical github.com hosts.

Source

Thrown at src/github_relay.rs:985

    /// API adapter: an HTTP request over the forwarded private socket. No upstream
    /// authentication headers are sent to the target or supplied by the target.
    pub(crate) async fn request(
        socket: &Path,
        method: Method,
        url: &Url,
        headers: &http::HeaderMap,
    ) -> Result<reqwest::Response> {
        if url.scheme() != "https"
            || !url.username().is_empty()
            || url.password().is_some()
            || url.port().is_some()
        {
            bail!("unsupported relay destination");
        }
        let prefix = match url.host_str() {
            Some("api.github.com") => "api",
            Some("github.com") => "web",
            _ => bail!("unsupported relay host"),
        };
        let mut relay_url = Url::parse(&format!("http://localhost/{prefix}{}", url.path()))?;
        relay_url.set_query(url.query());
        let (client, request_timeout) = adapter_client(socket).await?;
        let mut req = client.request(method, relay_url);
        for name in ["accept", "range", "if-range"] {
            if let Some(value) = headers.get(name) {
                req = req.header(name, value);
            }
        }
        send_adapter_request(req, request_timeout).await
    }

    // Obtain the initiating machine's policy, not the target's saved settings.
    // Discovery itself has a short fixed bound and bypasses broker request slots.
    async fn adapter_client(socket: &Path) -> Result<(Client, Duration)> {
        let builder = || {
            Client::builder()

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Use only https://api.github.com or https://github.com URLs with the relay; resolve asset downloads through the API instead of hitting CDN hosts directly.
  2. Correct host typos or replace mirror/GHES hosts with canonical github.com endpoints.
  3. If you need another host, fetch it with a plain HTTP client rather than the relay.

Example fix

// before
let url = Url::parse("https://raw.githubusercontent.com/foo/bar/main/file.txt")?;
// after
let url = Url::parse("https://api.github.com/repos/foo/bar/contents/file.txt")?;
Defensive patterns

Strategy: validation

Validate before calling

fn relay_host_prefix(url: &Url) -> Option<&'static str> {
    match url.host_str()? {
        "api.github.com" => Some("api"),
        "github.com" => Some("web"),
        _ => None,
    }
}

Prevention

When it happens

Trigger: Calling request with a host like ghe.example.com, codeload.github.com, objects.githubusercontent.com, raw.githubusercontent.com, or a misspelled github.com — anything other than exactly api.github.com or github.com.

Common situations: Following redirect URLs to asset/CDN hosts and passing those into request(); configuring a GHES instance expecting relay support; typos or localized mirror hosts in config; constructing URLs from user input that lands on non-API hosts.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/44347dec3996dbc2. Report an issue: GitHub.