{"record":{"id":"bd2c600e586abbb3","repo":"rathole-org/rathole","slug":"unexpected-type-of-hello","errorCode":null,"errorMessage":"Unexpected type of hello","messagePattern":"Unexpected type of hello","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/client.rs","lineNumber":429,"sourceCode":"            .connect(&remote_addr)\n            .await\n            .with_context(|| format!(\"Failed to connect to {}\", &self.remote_addr))?;\n        T::hint(&conn, SocketOpts::for_control_channel());\n\n        // Send hello\n        debug!(\"Sending hello\");\n        let hello_send =\n            Hello::ControlChannelHello(CURRENT_PROTO_VERSION, self.digest[..].try_into().unwrap());\n        conn.write_all(&bincode::serialize(&hello_send).unwrap())\n            .await?;\n        conn.flush().await?;\n\n        // Read hello\n        debug!(\"Reading hello\");\n        let nonce = match read_hello(&mut conn).await? {\n            ControlChannelHello(_, d) => d,\n            _ => {\n                bail!(\"Unexpected type of hello\");\n            }\n        };\n\n        // Send auth\n        debug!(\"Sending auth\");\n        let mut concat = Vec::from(self.service.token.as_ref().unwrap().as_bytes());\n        concat.extend_from_slice(&nonce);\n\n        let session_key = protocol::digest(&concat);\n        let auth = Auth(session_key);\n        conn.write_all(&bincode::serialize(&auth).unwrap()).await?;\n        conn.flush().await?;\n\n        // Read ack\n        debug!(\"Reading ack\");\n        match read_ack(&mut conn).await? {\n            Ack::Ok => {}\n            v => {","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/rathole-org/rathole/blob/a292f7ed5402f840415fc6a53827da2f34337856/src/client.rs#L411-L447","documentation":"After connecting to the server, the client reads a hello message and expects ControlChannelHello; any other hello variant triggers this bail. It means the remote peer answered on the control channel with unexpected data — typically not a rathole server at all, or a version/protocol mismatch (though version mismatch has its own error).","triggerScenarios":"read_hello returns a Hello variant that is not ControlChannelHello inside ControlChannel::run, immediately after TCP connect to remote_addr.","commonSituations":"remote_addr points at the wrong host or port (e.g. the HTTP port, an SSH daemon, or the rathole data port); a proxy or firewall returns a non-rathole banner; connecting a client to another client.","solutions":["Verify remote_addr points to the rathole server's control-channel port, not another service","Confirm the server is actually running and reachable at that address","Check for port conflicts — something else may be listening on the configured port","Test with a raw connection (nc host port) to see what the endpoint responds with"],"exampleFix":"// before (client.toml)\n[client]\nremote_addr = \"example.com:80\"  # wrong port, HTTP server answers\n\n// after\n[client]\nremote_addr = \"example.com:2333\"  # rathole server's control port","handlingStrategy":"validation","validationCode":"// Probe the endpoint before pointing rathole at it:\nnc -vz example.com 2333 && timeout 3 bash -c 'exec 3<>/dev/tcp/example.com/2333; head -c 64 <&3' | xxd | head\n// Non-rathole banner bytes mean wrong host/port.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Point remote_addr at the server's control port, never at other services on the host","Confirm the server process is up (systemctl status rathole / docker ps)","Use distinct ports for control and other daemons to avoid conflicts"],"tags":["rust","network","handshake","protocol"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"a292f7ed5402f840415fc6a53827da2f34337856","analyzedAt":"2026-09-07T09:56:55.739Z","contentChangedAt":"2026-09-07T09:56:55.739Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}