{"record":{"id":"e581e566018542c6","repo":"tracel-ai/burn","slug":"failed-to-close-websocket-stream","errorCode":null,"errorMessage":"Failed to close WebSocket stream","messagePattern":"Failed to close WebSocket stream","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/burn-communication/src/external_comm.rs","lineNumber":133,"sourceCode":"                max_downloads,\n                cur_download_count: 0,\n            },\n        );\n        core::mem::drop(exposed_tensors);\n        self.new_tensor_notify.notify_waiters();\n    }\n\n    pub async fn close(&self) {\n        // Send a closing message to every open WebSocket stream\n\n        let mut streams = self.channels.lock().await;\n        for (_, stream) in streams.drain() {\n            let mut stream = stream.lock().await;\n\n            stream\n                .close()\n                .await\n                .expect(\"Failed to close WebSocket stream\");\n        }\n    }\n\n    /// Downloads a tensor that is exposed on another server. Requires a Tokio 1.x runtime\n    ///\n    /// Returns None if the peer closes the connection\n    pub async fn download_tensor(\n        &self,\n        remote: Address,\n        transfer_id: TensorTransferId,\n    ) -> Option<TensorData> {\n        log::info!(\"Downloading tensor from {remote:?}\");\n\n        let stream = self.get_data_stream(remote).await;\n        let mut stream = stream.lock().await;\n\n        // Send the download request with the download id\n        let bytes: bytes::Bytes =","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-communication/src/external_comm.rs#L115-L151","documentation":"This panic happens in the close() method of the external WebSocket communication module when closing one of the tracked peer streams fails. Each stream is locked, and stream.close().await is expected to succeed; a failure means the WebSocket transport could not perform the close handshake (connection already dead, broken underlying socket, or task runtime issue).","triggerScenarios":"Calling close() (server/communicator shutdown) when a peer connection has already been severed abruptly (peer process died, network drop, TCP reset), so the websocket close handshake errors.","commonSituations":"Shutting down a tensor-sharing server while remote peers have disconnected; network partitions or firewall kills during long training runs; peer crash leaving half-open sockets that fail on graceful close.","solutions":["Treat close failures as non-fatal: replace expect with a logged warning, since the socket is being discarded anyway.","Check peer liveness and clean stale/dead connections from the streams map before closing.","Ensure the tokio runtime is running when close() is awaited — calling it outside a runtime can error.","Add keepalive/ping timeouts so dead connections are pruned before shutdown."],"exampleFix":"// before\nstream.close().await.expect(\"Failed to close WebSocket stream\");\n// after\nif let Err(e) = stream.close().await {\n    log::warn!(\"failed to close websocket stream gracefully: {e}\");\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = stream.close().await {\n    log::warn!(\"websocket close failed (ignoring): {e}\");\n}","preventionTips":["Treat close errors as non-fatal — the socket is being discarded anyway.","Prune dead connections periodically instead of only at shutdown.","Ensure close() runs inside an active tokio runtime."],"tags":["websocket","network","panic","shutdown"],"backgroundTag":"websocket-close-failed","analyzedSha":"d16f7ba2ed0d41408189384044cc886fb4c8f957","analyzedAt":"2026-09-05T13:19:14.260Z","contentChangedAt":"2026-09-05T13:19:14.260Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}