ducaale/xh · error

Invalid proxy URL ' ' for protocol

Error message

Invalid proxy URL '{}' for protocol '{}': {}

What it means

FromStr for the --proxy CLI argument splits its input into <PROTOCOL>:<PROXY_URL>, then asks reqwest to parse the URL part. When reqwest::Url::try_from fails (relative URL, bad scheme, unparseable characters), this error wraps the raw URL, the protocol key, and reqwest's own parse message.

Solutions

  1. Include an absolute scheme in the proxy URL, e.g. --proxy http:http://127.0.0.1:8080
  2. Quote the whole argument in your shell so spaces/special chars survive: --proxy 'all:http://proxy.local:3128'
  3. Check reqwest's message at the end of the error for the exact parse failure (relative URL without base, invalid port, etc.) and fix that part

Example fix

// before
xh --proxy http:127.0.0.1:8080 GET https://example.com
// after
xh --proxy http:http://127.0.0.1:8080 GET https://example.com
Defensive patterns

Strategy: validation

Validate before calling

fn validate_proxy_arg(arg: &str) -> Result<(), String> {
    let (protocol, url) = arg.split_once(':')
        .ok_or("must be <PROTOCOL>:<PROXY_URL>")?;
    match protocol.to_lowercase().as_str() {
        "http" | "https" | "all" => {},
        other => return Err(format!("unknown protocol {}", other)),
    }
    let parsed = reqwest::Url::parse(url).map_err(|e| e.to_string())?;
    if parsed.scheme().is_empty() { return Err("missing URL scheme".into()); }
    Ok(())
}

Type guard

fn is_absolute_url(s: &str) -> bool {
    reqwest::Url::parse(s).map(|u| u.has_host()).unwrap_or(false)
}

Try / catch

match ProxyArg::from_str(&arg) {
    Ok(p) => p,
    Err(e) => eprintln!("--proxy rejected: {e}; expected <PROTOCOL>:<SCHEME>://host:port"),
}

Prevention

When it happens

Trigger: Passing --proxy http:localhost:8080 (no scheme) or --proxy all:ht tp://bad url or any PROXY_URL that reqwest cannot parse into an absolute URL.

Common situations: Typos in the proxy address, forgetting the http(s):// scheme, quoting problems in shell where spaces or colons break the argument, copy-pasting a proxy string like host:port without a URL scheme.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13). Data as JSON: /api/errors/66f0cce644031b44. Report an issue: GitHub.

Appendix: source

Thrown at src/cli.rs:1231

    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Proxy {
    Http(Url),
    Https(Url),
    All(Url),
}

impl FromStr for Proxy {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> anyhow::Result<Self> {
        let split_arg: Vec<&str> = s.splitn(2, ':').collect();
        match split_arg[..] {
            [protocol, url] => {
                let url = reqwest::Url::try_from(url).map_err(|e| {
                    anyhow!(
                        "Invalid proxy URL '{}' for protocol '{}': {}",
                        url,
                        protocol,
                        e
                    )
                })?;

                match protocol.to_lowercase().as_str() {
                    "http" => Ok(Proxy::Http(url)),
                    "https" => Ok(Proxy::Https(url)),
                    "all" => Ok(Proxy::All(url)),
                    _ => Err(anyhow!("Unknown protocol to set a proxy for: {}", protocol)),
                }
            }
            _ => Err(anyhow!(
                "The value passed to --proxy should be formatted as <PROTOCOL>:<PROXY_URL>"
            )),
        }

View on GitHub (pinned to 2404aceecc)