rathole-org/rathole · error
proxy url should have host field
Error message
proxy url should have host field
What it means
tcp_connect_with_proxy connects to the SOCKS5 proxy itself using url.host_str().expect(...). If the proxy Url lacks a host component, this panics at src/helper.rs:118. A proxy URL without a host cannot be dialed, so the invariant is enforced with an expect.
Solutions
- Provide a complete proxy URL including host, e.g. `socks5://proxy.example.com:1080`.
- Check the proxy environment variable / CLI flag value for typos or missing host.
- Validate the URL with Url::parse and assert host_str().is_some() before starting connections.
- If credentials are used, ensure the format `socks5://user:pass@host:port` is preserved.
Example fix
// before let proxy = "socks5://:1080"; // no host -> panic // after let proxy = "socks5://127.0.0.1:1080";
Defensive patterns
Strategy: validation
Validate before calling
let url = Url::parse(proxy_str).map_err(|e| anyhow!("bad proxy url: {}", e))?;
if url.host_str().is_none() {
anyhow::bail!("proxy url '{}' must include a host", proxy_str);
} Type guard
fn valid_proxy_url(u: &Url) -> bool {
u.host_str().is_some()
} Prevention
- Store full proxy URLs including scheme, host and port
- Validate proxy env vars at startup
- Avoid hand-editing proxy URLs in production configs
When it happens
Trigger: Passing a proxy option whose URL has no host — e.g. `socks5://:1080`, a malformed URL, or an empty proxy string parsed to a host-less Url.
Common situations: Typo in the proxy URL (missing host between scheme and port); environment variable ALL_PROXY/HTTP_PROXY set to a malformed value; templated configs where the proxy host variable was empty.
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 rathole-org/rathole@a292f7ed54 (2026-09-07).
Data as JSON: /api/errors/1687e6d0c31c696e.
Report an issue: GitHub.
Appendix: source
Thrown at src/helper.rs:118
}
}
};
let s = UdpSocket::bind(bind_addr).await?;
s.connect(socket_addr).await?;
s.connect(socket_addr).await?;
Ok(s)
}
/// Create a TcpStream using a proxy
/// e.g. socks5://user:pass@127.0.0.1:1080 http://127.0.0.1:8080
pub async fn tcp_connect_with_proxy(
addr: &AddrMaybeCached,
proxy: Option<&Url>,
) -> Result<TcpStream> {
if let Some(url) = proxy {
let addr = &addr.addr;
let mut s = TcpStream::connect((
url.host_str().expect("proxy url should have host field"),
url.port().expect("proxy url should have port field"),
))
.await?;
let auth = if !url.username().is_empty() || url.password().is_some() {
Some(async_socks5::Auth {
username: url.username().into(),
password: url.password().unwrap_or("").into(),
})
} else {
None
};
match url.scheme() {
"socks5" => {
async_socks5::connect(&mut s, host_port_pair(addr)?, auth).await?;
}
"http" => {
let (host, port) = host_port_pair(addr)?;View on GitHub (pinned to a292f7ed54)