rathole-org/rathole · error · anyhow::Error

{}

Error message

{}

What it means

Fires in the client's control-channel run loop after sending Auth(service_token-derived session key): the server replied with an Ack other than Ack::Ok (e.g. ServiceNotExist or AuthFailed). The client wraps the ack variant in a generic anyhow error, so the displayed message is the ack's Debug/Display text. It means the server rejected the control-channel establishment for this service.

Solutions

  1. Inspect the ack variant in the message: ServiceNotExist means the service name is unknown to the server; AuthFailed means the token does not match
  2. Re-check that the client's service token equals the server's token for the same service
  3. Confirm the service is defined in the server config and the server was reloaded after changes
  4. Replace the generic anyhow!("{}", v) with a typed error for clearer diagnostics
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at src/client.rs:448 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of rathole-org/rathole@a292f7ed54 (2026-09-07). Data as JSON: /api/errors/d28f8754b93a9145. Report an issue: GitHub.

Appendix: source

Thrown at src/client.rs:448

            }
        };

        // Send auth
        debug!("Sending auth");
        let mut concat = Vec::from(self.service.token.as_ref().unwrap().as_bytes());
        concat.extend_from_slice(&nonce);

        let session_key = protocol::digest(&concat);
        let auth = Auth(session_key);
        conn.write_all(&bincode::serialize(&auth).unwrap()).await?;
        conn.flush().await?;

        // Read ack
        debug!("Reading ack");
        match read_ack(&mut conn).await? {
            Ack::Ok => {}
            v => {
                return Err(anyhow!("{}", v))
                    .with_context(|| format!("Authentication failed: {}", self.service.name));
            }
        }

        // Channel ready
        info!("Control channel established");

        // Socket options for the data channel
        let socket_opts = SocketOpts::from_client_cfg(&self.service);
        let data_ch_args = Arc::new(RunDataChannelArgs {
            session_key,
            remote_addr,
            connector: self.transport.clone(),
            socket_opts,
            service: self.service.clone(),
        });

        loop {

View on GitHub (pinned to a292f7ed54)