Reqwest v0.12.20 failed when accessing ipv6 via SOCKS5 proxy
When using reqwest v0.12.20 to access a TLS v1.3 network through a SOCKS5 proxy, an error occurs.
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = reqwest::Client::builder()
.proxy(reqwest::Proxy::all("socks5://127.0.0.1:1080")?)
.build()?;
let res = client.get("https://openrouter.ai/api/v1/models").send().await?;
let data: serde_json::Value = res.json().await?;
println!("{data}");
Ok(())
}
[dependencies]
anyhow = "1"
serde_json = "1"
reqwest = { version = "0.12.20", features = ["json", "socks"] }
tokio = { version = "1", features = ["full"] }
Error: error sending request
Caused by:
0: client error (Connect)
1: invalid authority
If you downgrade reqwest to v0.12.19, it will work properly.
-reqwest = { version = "0.12.20", features = ["json", "socks"] }
+reqwest = { version = "=0.12.19", features = ["json", "socks"] }
Maybe related to https://github.com/seanmonstar/reqwest/pull/2726/ and https://github.com/seanmonstar/reqwest/pull/2732
I tried it on macOS and it worked fine. Maybe it's a dependency cache issue? I've already run cargo update
I've tested it on macOS as well, and the same issue occurs.
Reqwest was upgraded to v0.12.21, but the bug still exists.
There's no issue with the SOCKS5. If you change the URL to one using TLS v1.2, such as (https://httpbin.org/ip), everything works fine.
Are you able to turn on trace logs for reqwest?
2025-07-01T00:20:34.002121Z TRACE hyper_util::client::legacy::pool: checkout waiting for idle connection: ("https", openrouter.ai)
2025-07-01T00:20:34.002777Z TRACE hyper_util::client::legacy::pool: checkout dropped for ("https", openrouter.ai)
Error: error sending request for url (https://openrouter.ai/api/v1/models)
Caused by:
0: client error (Connect)
1: error connecting to socks proxy
2: invalid authority
Hm, reqwest uses just the log crate at the moment. But I think I see where the error may be coming from, it might be when the destination resolves to IPv6.
2025-07-01T00:20:34.002121Z TRACE hyper_util::client::legacy::pool: checkout waiting for idle connection: ("https", openrouter.ai) 2025-07-01T00:20:34.002777Z TRACE hyper_util::client::legacy::pool: checkout dropped for ("https", openrouter.ai) Error: error sending request for url (https://openrouter.ai/api/v1/models) Caused by: 0: client error (Connect) 1: error connecting to socks proxy 2: invalid authority
Can you try socks5h? It helps to troubleshoot DNS resolution issues
socks5h did work
2025-07-01T00:33:07.545940Z TRACE hyper_util::client::legacy::pool: checkout waiting for idle connection: ("https", openrouter.ai)
2025-07-01T00:33:07.546018Z TRACE hyper_util::client::legacy::connect::http: Http::connect; scheme=Some("socks5h"), host=Some("127.0.0.1"), port=Some(Port(1080))
2025-07-01T00:33:07.546041Z DEBUG hyper_util::client::legacy::connect::http: connecting to 127.0.0.1:1080
2025-07-01T00:33:07.546166Z DEBUG hyper_util::client::legacy::connect::http: connected to 127.0.0.1:1080
2025-07-01T00:33:08.100522Z TRACE hyper_util::client::legacy::client: http1 handshake complete, spawning background dispatcher task
2025-07-01T00:33:08.100582Z TRACE hyper_util::client::legacy::client: waiting for connection to be ready
2025-07-01T00:33:08.100761Z TRACE hyper_util::client::legacy::client: connection is ready
2025-07-01T00:33:08.100798Z TRACE hyper_util::client::legacy::pool: checkout dropped for ("https", openrouter.ai)
2025-07-01T00:33:08.860793Z TRACE hyper_util::client::legacy::pool: put; add idle connection for ("https", openrouter.ai)
2025-07-01T00:33:08.860906Z DEBUG hyper_util::client::legacy::pool: pooling idle connection for ("https", openrouter.ai)
2025-07-01T00:33:08.862217Z TRACE hyper_util::client::legacy::pool: idle interval checking for expired
{"data":[{"architecture":{"input_modalities":["text"],"instruct_type":null,"modality":"text->text","output_modalities":["text"],"tokenizer":"Other"},"canonical_slug":"baidu/e
Since I don't have an IPv6 environment. I looked through the code carefully. The source of the error may be due to an error in parsing the Uri: https://github.com/seanmonstar/reqwest/blob/b739726c4a2e47470346777062817af4f35feef2/src/connect.rs#L1309
Maybe you can debug the error point to solve the problem faster.
This should be a problem caused by converting IPv6 SocketAddr directly to String. URI requires [] to include...
mod tests {
use http::Uri;
use std::net::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
#[test]
fn test_socketaddr_ip_to_uri_format() {
let port = 8080;
// IPv4 address: direct concatenation should parse successfully
let ipv4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port);
let host = ipv4.ip().to_string();
let uri = format!("http://{}:{}", host, port).parse::<Uri>();
assert!(uri.is_ok(), "IPv4 direct concatenation should be parsed successfully");
// IPv6 address without brackets: should fail to parse
let ipv6 = SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), port);
let host = ipv6.ip().to_string();
let uri = format!("http://{}:{}", host, port).parse::<Uri>();
assert!(uri.is_err(), "IPv6 without brackets should fail to parse");
// IPv6 address with brackets: should parse successfully
let host = format!("[{}]", ipv6.ip());
let uri = format!("http://{}:{}", host, port).parse::<Uri>();
assert!(uri.is_ok(), "IPv6 with brackets should be parsed successfully");
}
}
#2753 solved the problem.