ducaale/xh · error

couldn't extract host from url

Error message

couldn't extract host from url

What it means

When loading a named session, xh derives the session filename from the request URL's host (and optional port). If the Url has no host, or the host is '.' or '..', no usable filename can be formed, so path_from_url errors and load_session aborts.

Solutions

  1. Include scheme and host in the URL, e.g. https://api.example.com instead of a relative path
  2. Validate the URL parses to a Some(host) before invoking with --session
  3. Fix environment/variable substitution that leaves the host empty or '.'
  4. If connecting to localhost, use http://localhost:8080 explicitly

Example fix

// before
xh --session=mysess GET :8080/api/items
// after
xh --session=mysess GET http://localhost:8080/api/items
Defensive patterns

Strategy: validation

Validate before calling

if let Ok(u) = Url::parse(url) {
    if u.host_str().is_none() || matches!(u.host_str(), Some(".") | Some("..")) {
        eprintln!("URL must include a scheme and host for --session");
        std::process::exit(2);
    }
}

Type guard

fn url_has_host(u: &Url) -> bool {
    u.host_str().map(|h| h != "." && h != "..").unwrap_or(false)
}

Try / catch

match result {
    Err(e) if e.to_string().contains("extract host from url") => {
        eprintln!("provide a full URL like https://host:port");
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling load_session/--session with a URL whose host cannot be parsed, e.g. a relative URL without scheme (`xh --session=name :8080/path` variants), an empty or malformed URL, or a URL whose host normalizes to '.' or '..'.

Common situations: Forgetting the scheme in the URL so it parses as a path; programmatic use building Url from user input; automated scripts substituting empty host variables.

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/c17969ab25643fc5. Report an issue: GitHub.

Appendix: source

Thrown at src/session.rs:378

    }
}

fn xh_version() -> String {
    if test_mode() {
        "0.0.0".into()
    } else {
        env!("CARGO_PKG_VERSION").into()
    }
}

fn is_path(value: &OsString) -> bool {
    value.to_string_lossy().contains(std::path::is_separator)
}

fn path_from_url(url: &Url) -> Result<String> {
    match (url.host_str(), url.port()) {
        (Some("."), _) | (Some(".."), _) | (None, _) => {
            Err(anyhow!("couldn't extract host from url"))
        }
        (Some(host), Some(port)) => Ok(format!("{host}_{port}")),
        (Some(host), None) => Ok(host.into()),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use anyhow::Result;
    use reqwest::header::HeaderValue;

    fn load_session_from_str(s: &str) -> Result<Session> {
        Ok(Session {
            url: Url::parse("http://example.net")?,
            content: serde_json::from_str::<Content>(s)?.migrate(),
            path: PathBuf::new(),

View on GitHub (pinned to 2404aceecc)