{"record":{"id":"465a93e3b1863671","repo":"rustdesk/rustdesk-server","slug":"err-to-string","errorCode":null,"errorMessage":"err.to_string()","messagePattern":"err\\.to_string\\(\\)","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"warning","filePath":"src/relay_server.rs","lineNumber":665,"sourceCode":"    fn set_raw(&mut self) {\n        self.set_raw();\n    }\n}\n\n#[async_trait]\nimpl StreamTrait for tokio_tungstenite::WebSocketStream<TcpStream> {\n    async fn recv(&mut self) -> Option<Result<BytesMut, Error>> {\n        if let Some(msg) = self.next().await {\n            match msg {\n                Ok(msg) => {\n                    match msg {\n                        tungstenite::Message::Binary(bytes) => {\n                            Some(Ok(bytes[..].into())) // to-do: poor performance\n                        }\n                        _ => Some(Ok(BytesMut::new())),\n                    }\n                }\n                Err(err) => Some(Err(Error::new(std::io::ErrorKind::Other, err.to_string()))),\n            }\n        } else {\n            None\n        }\n    }\n\n    async fn send_raw(&mut self, bytes: Bytes) -> ResultType<()> {\n        Ok(self\n            .send(tungstenite::Message::Binary(bytes.to_vec()))\n            .await?) // to-do: poor performance\n    }\n\n    fn is_ws(&self) -> bool {\n        true\n    }\n\n    fn set_raw(&mut self) {}\n}","sourceCodeStart":647,"sourceCodeEnd":683,"githubUrl":"https://github.com/rustdesk/rustdesk-server/blob/a7736be5e40f85bfc141120dce587e836e5d4b80/src/relay_server.rs#L647-L683","documentation":"In the relay server's WebSocket-to-stream adapter, when the underlying websocket read fails, the error is converted into an std::io::Error of kind Other carrying err.to_string() as its message. Downstream code surfaces this io error (message = the tungstenite error text) when the websocket connection with the peer breaks.","triggerScenarios":"The tungstenite websocket read returns Err - connection closed by peer, TCP reset, protocol violation, or TLS failure - while bridging the websocket into the relay byte stream.","commonSituations":"Client disconnects abruptly mid-relay (network drop, app kill); proxy/load-balancer terminating idle websocket connections; tungstenite protocol/version mismatch; TLS certificate problems on wss endpoints.","solutions":["Treat this as an expected disconnect on the client side: reconnect and re-pair the relay session with retry/backoff.","Inspect the wrapped tungstenite message (it is preserved verbatim in the io::Error) to identify close/reset vs protocol error.","Enable websocket ping/pong or lower idle timeouts on proxies so intermediaries do not silently kill connections.","Check TLS certificates and websocket upgrade support if errors cluster on wss:// endpoints."],"exampleFix":"// client side: resilient reconnect\nloop {\n    match connect_and_relay().await {\n        Ok(()) => break,\n        Err(e) if e.kind() == std::io::ErrorKind::Other => {\n            tokio::time::sleep(backoff).await;\n            backoff = (backoff * 2).min(MAX_BACKOFF);\n        }\n        Err(e) => return Err(e),\n    }\n}","handlingStrategy":"retry","validationCode":"// pre-flight: confirm websocket endpoint is reachable and upgrades correctly\nlet (ws, _) = tokio_tungstenite::connect_async(url).await?; // fails fast before relay starts","typeGuard":null,"tryCatchPattern":"match session.next().await {\n    Ok(Ok(_msg)) => { /* forward bytes */ }\n    Ok(Err(e)) => reconnect_with_backoff(Error::new(std::io::ErrorKind::Other, e.to_string())),\n    Err(e) => reconnect_with_backoff(e.into()),\n}","preventionTips":["Use websocket ping/pong frames to keep intermediaries from killing idle connections.","Configure proxies/LBs with websocket-friendly idle timeouts.","Implement client-side reconnect with exponential backoff around relay sessions.","Log the wrapped tungstenite error text to distinguish closes from protocol errors."],"tags":["websocket","network","relay","io-error"],"backgroundTag":"network-request-failed","analyzedSha":"a7736be5e40f85bfc141120dce587e836e5d4b80","analyzedAt":"2026-09-09T21:56:29.933Z","contentChangedAt":"2026-09-09T21:56:29.933Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}