Onion service connections often time out
On the forum, a user reports that TorClient::connect() frequently times out when connecting to an onion address.
I was able to reproduce the issue locally. I've been using this simplified version of the repro from the forum post:
use arti_client::{TorClient, TorClientConfig};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
const ONION_ADDR: &'static str = "duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion";
#[tokio::main]
async fn main() {
let subscriber = tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::DEBUG)
.finish();
tracing::subscriber::set_global_default(subscriber).unwrap();
let mut config_builder = TorClientConfig::builder();
config_builder.address_filter().allow_onion_addrs(true);
let config = config_builder.build().unwrap();
let tor_client = TorClient::create_bootstrapped(config).await.unwrap();
// XXX this often times out
let mut stream = tor_client.connect((ONION_ADDR, 80)).await.unwrap();
let req = format!("GET / HTTP/1.1\r\nHost: {ONION_ADDR}\r\nConnection: close\r\n");
stream.write_all(req.as_bytes()).await.unwrap();
stream.flush().await.unwrap();
let mut buf = Vec::new();
stream.read_to_end(&mut buf).await.unwrap();
println!("{}", String::from_utf8_lossy(&buf));
}
Cargo.toml:
[package]
name = "onion-svc-test"
version = "0.1.0"
edition = "2024"
[dependencies]
arti-client = { version = "0.41.0", features = ["onion-service-client"] }
env_logger = "0.11.10"
tokio = { version = "1.52.0", features = ["macros"] }
tracing = "0.1.44"
tracing-subscriber = "0.3.23"
For me, the issue is intermittent, but running it in a loop (
for i in {1..10}; do ./target/release/onion-svc-test > /dev/null 2>&1; echo "run $i status: $?"; done), usually causes at least 1-2 failures (out of 10).
In the logs, I can see it usually times out while fetching the service descriptor:
026-04-15T17:43:25.631556Z DEBUG tor_circmgr::build: Spawning reactor...
2026-04-15T17:43:25.825917Z DEBUG tor_hsclient::connect: failed hsdir desc fetch for […]zad.onion from lSu9AbBH7kqGGbx5aI3deSvlEimo+UWi++wc5HKSj7c/$6796e53160714d908b39bcb0058cf488ff940336 error=timed out
2026-04-15T17:43:25.849167Z DEBUG tor_circmgr::hspool: launching 2 NAIVE and 0 GUARDED circuits
2026-04-15T17:43:25.909357Z DEBUG tor_circmgr::build: Spawning reactor...
2026-04-15T17:43:26.248851Z DEBUG tor_hsclient::connect: failed hsdir desc fetch for […]zad.onion from Johg7fp+z2KekVA6pIMet2uB6xFpj7PTUnd19eTFKi8/$92a01038972f368200b03dc0d194b217ba441d55 error=directory error error.sources=[HTTP status code 404: "Not found"]
2026-04-15T17:43:26.291042Z DEBUG tor_circmgr::build: Spawning reactor...
2026-04-15T17:43:26.504428Z DEBUG tor_hsclient::connect: failed hsdir desc fetch for […]zad.onion from o4a/gH+yI+BJjOA29hN0L3GSKqKV6lXwpuSKx28DKrg/$aef6c1fba0fc16f4931638bf065085b974d3e90f error=circuit failed error.sources=[Circuit 0.4 took too long to build]
2026-04-15T17:43:26.673398Z DEBUG tor_circmgr::hspool: Unable to build preemptive circuit for onion services error=Circuit took too long to build
2026-04-15T17:43:26.732334Z DEBUG tor_circmgr::build: Spawning reactor...
2026-04-15T17:43:26.759364Z DEBUG tor_hsclient::connect: failed hsdir desc fetch for […]zad.onion from NtWi2fdtXOsvEK/uNU5jpfqyc7ObFNxYXwbXliovrdc/$5a177e1275f89b36201e7d0a7f3cba5700745265 error=circuit failed error.sources=[Circuit 1.2 took too long to build]
2026-04-15T17:43:26.759426Z DEBUG tor_hsclient::state: HS connection failure for […]zad.onion error=Unable to download hidden service descriptor
Occasionally, it times out at other points in the rendezvous process:
2026-04-15T17:45:41.803537Z DEBUG tor_circmgr::build: Spawning reactor...
2026-04-15T17:45:41.844678Z DEBUG tor_hsclient::connect: hs conn to […]zad.onion: attempt failed error=Failed to obtain circuit to introduction point #1 error.sources=[Circuit took too long to build]
2026-04-15T17:45:41.844796Z DEBUG tor_hsclient::state: HS connection failure for […]zad.onion error=Unable to connect to hidden service using any Rendezvous Point / Introduction Point error.sources=[Tried to make circuit to hidden service 9 times, but all attempts failed
Attempt 1: Failed to obtain circuit to introduction point #6: Circuit 1.0 took too long to build
Attempt 2: Failed to obtain circuit to introduction point #2: Circuit 0.5 took too long to build
Attempt 3: Communication with introduction point #8 took too long
Attempt 4: Failed to obtain any circuit to use as a rendezvous circuit: Circuit took too long to build
Attempt 5: Failed to obtain any circuit to use as a rendezvous circuit: Circuit took too long to build
Attempt 6: Failed to obtain any circuit to use as a rendezvous circuit: Circuit took too long to build
Attempt 7: Failed to obtain circuit to introduction point #10: Circuit 1.1 took too long to build
Attempt 8: Failed to obtain circuit to introduction point #7: Circuit took too long to build
Attempt 9: Failed to obtain circuit to introduction point #1: Circuit took too long to build]
thread 'main' (71900) panicked at src/main.rs:19:65:
called `Result::unwrap()` on an `Err` value: Error { detail: ObtainHsCircuit { hsid: HsId([…]zad.onion), cause: Failed(RetryError { doing: "make circuit to hidden service", errors: [(Single(1), IntroductionCircuitObtain { error: CircTimeout(Some(UniqId { chan: 1, circ: 0 }
)), intro_index: IntroPtIndex(5) }, Instant { tv_sec: 31268, tv_nsec: 380761518 }), (Single(2), IntroductionCircuitObtain { error: CircTimeout(Some(UniqId { chan: 0, circ: 5 })), intro_index: IntroPtIndex(1) }, Instant { tv_sec: 31268, tv_nsec: 633888933 }), (Single(3), In
troductionTimeout { intro_index: IntroPtIndex(7) }, Instant { tv_sec: 31269, tv_nsec: 202124275 }), (Single(4), RendezvousCircuitObtain { error: CircTimeout(None) }, Instant { tv_sec: 31269, tv_nsec: 641942453 }), (Single(5), RendezvousCircuitObtain { error: CircTimeout(No
ne) }, Instant { tv_sec: 31270, tv_nsec: 84232544 }), (Single(6), RendezvousCircuitObtain { error: CircTimeout(None) }, Instant { tv_sec: 31270, tv_nsec: 545244924 }), (Single(7), IntroductionCircuitObtain { error: CircTimeout(Some(UniqId { chan: 1, circ: 1 })), intro_inde
x: IntroPtIndex(9) }, Instant { tv_sec: 31271, tv_nsec: 36297539 }), (Single(8), IntroductionCircuitObtain { error: CircTimeout(None), intro_index: IntroPtIndex(6) }, Instant { tv_sec: 31271, tv_nsec: 472089182 }), (Single(9), IntroductionCircuitObtain { error: CircTimeout
(None), intro_index: IntroPtIndex(0) }, Instant { tv_sec: 31271, tv_nsec: 909806254 })], n_errors: 9, first_error_at: Some(SystemTime { tv_sec: 1776275138, tv_nsec: 315702979 }) }) } }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
We have a lot of other, possibly related onion service issues, so this might be a dupe.