{"record":{"id":"b4b9a0070cac9f6a","repo":"nautechsystems/nautilus_trader","slug":"writer-task-dropped-response-channel-b4b9a0","errorCode":null,"errorMessage":"Writer task dropped response channel","messagePattern":"Writer task dropped response channel","errorType":"exception","errorClass":"TransportError","httpStatus":null,"severity":"error","filePath":"crates/network/src/websocket/client.rs","lineNumber":1362,"sourceCode":"        // back to ACTIVE. Buffered messages stay in the writer task and replay later.\n        let (tx, rx) = tokio::sync::oneshot::channel();\n        if let Err(e) = self.writer_tx.send(WriterCommand::Update(new_writer, tx)) {\n            log::error!(\"{e}\");\n            return Err(TransportError::Io(std::io::Error::new(\n                std::io::ErrorKind::BrokenPipe,\n                format!(\"Failed to send update command: {e}\"),\n            )));\n        }\n\n        // Wait for writer to confirm it accepted the new socket\n        let connection_epoch = match rx.await {\n            Ok(connection_epoch) => {\n                log::debug!(\"Writer confirmed socket update: epoch={connection_epoch}\");\n                connection_epoch\n            }\n            Err(e) => {\n                log::error!(\"Writer dropped update channel: {e}\");\n                return Err(TransportError::Io(std::io::Error::new(\n                    std::io::ErrorKind::BrokenPipe,\n                    \"Writer task dropped response channel\",\n                )));\n            }\n        };\n\n        // Delay before closing connection\n        dst::time::sleep(Duration::from_millis(GRACEFUL_SHUTDOWN_DELAY_MS)).await;\n\n        if ConnectionMode::from_atomic(&self.connection_mode).is_disconnect() {\n            log::debug!(\"Reconnect aborted mid-flight (after delay)\");\n            return Ok(ReconnectOutcome::Aborted);\n        }\n\n        if let Some(read_fence) = self.read_fence.take() {\n            read_fence.invalidate();\n        }\n","sourceCodeStart":1344,"sourceCodeEnd":1380,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/network/src/websocket/client.rs#L1344-L1380","documentation":"When the writer task receives WriterCommand::Update it replies on a oneshot channel with the new connection epoch. If the reply fails, the writer task dropped the responder, meaning it exited between receiving the command and acknowledging the socket swap. The client cannot confirm the writer is now using the new socket, so reconnect_with_outcome fails with this BrokenPipe error rather than transitioning to ACTIVE on an unconfirmed state.","triggerScenarios":"rx.await returning RecvError because the writer task dropped tx after receiving WriterCommand::Update — typically due to a panic or early return inside the writer loop while processing the update.","commonSituations":"Writer task panics while constructing the new sink/stream from the new socket; writer task racing shutdown; a bug in the socket-swap path under specific socket states (e.g. already-closed stream).","solutions":["Inspect writer task logs for a panic between receiving Update and replying; fix the panicking socket-swap code","Recreate the client (or rerun full reconnect) so a fresh writer task backs the new socket","Ensure the writer task always sends on the oneshot (including on its internal error paths) before exiting","Check for races with client shutdown and serialize disconnect/reconnect paths"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_broken_pipe(e: &TransportError) -> bool {\n    matches!(e, TransportError::Io(io) if io.kind() == std::io::ErrorKind::BrokenPipe)\n}","tryCatchPattern":"match reconnect_with_outcome().await {\n    Err(e) if is_broken_pipe(&e) => {\n        // writer dropped the oneshot: treat client as unusable and rebuild\n        client = rebuild_client(config).await?;\n    }\n    r => r?,\n}","preventionTips":["Make the writer task always respond on the oneshot before any early return","Audit the socket-swap code path for panics with closed/odd socket states","Serialize shutdown and reconnect so the writer cannot exit mid-update"],"tags":["network","websocket","broken-pipe","oneshot-channel","rust"],"backgroundTag":"broken-pipe","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}