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
- 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.
- Correct host typos or replace mirror/GHES hosts with canonical github.com endpoints.
- 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
- Only send api.github.com and github.com URLs to the relay.
- Resolve asset/CDN downloads via the API endpoints rather than following raw hosts.
- Normalize user/config-supplied GitHub URLs to canonical hosts before relaying.
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
- unsupported GitHub operation
- unsupported query parameter
- unsupported relay destination
- relay concurrency must be between 1 and 32
- expected a GitHub repository in OWNER/REPO form
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/44347dec3996dbc2.
Report an issue: GitHub.