{"record":{"id":"b3b99e239a7aac9f","repo":"nautechsystems/nautilus_trader","slug":"errors-join-b3b99e","errorCode":null,"errorMessage":"{errors.join(\"; \")}","messagePattern":"\\{errors\\.join\\(\"; \"\\)\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/websocket/pool.rs","lineNumber":800,"sourceCode":"                false\n            }\n        };\n\n        if let Err(e) = close.shard_mut().client.disconnect().await {\n            let error = format!(\"market shard {id} disconnect failed: {e}\");\n            self.state.lock().shutdown_errors.push(error);\n        }\n\n        if forwarder_stopped && !close.shard_mut().client.has_task() {\n            close.complete();\n        }\n\n        let errors = std::mem::take(&mut self.state.lock().shutdown_errors);\n\n        if errors.is_empty() {\n            Ok(())\n        } else {\n            anyhow::bail!(errors.join(\"; \"))\n        }\n    }\n\n    #[cfg(test)]\n    fn subscription_count_for_test(&self) -> usize {\n        self.state.lock().assignments.len()\n    }\n}\n\nfn should_forward_from_shard(message: &PolymarketWsMessage, is_primary: bool) -> bool {\n    is_primary\n        || !matches!(\n            message,\n            PolymarketWsMessage::Market(\n                MarketWsMessage::NewMarket(_) | MarketWsMessage::MarketResolved(_)\n            )\n        )\n}","sourceCodeStart":782,"sourceCodeEnd":818,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/websocket/pool.rs#L782-L818","documentation":"close_shard collects per-shard shutdown errors accumulated in the pool state (shutdown_errors) and, instead of returning them one by one, joins them with '; ' into a single anyhow error. The message is thus a list of every error encountered while shutting down the shard's tasks/streams.","triggerScenarios":"Calling close_shard (directly or via subscribe_one, unsubscribe_one, assign, or pool shutdown) when the shard's forwarder or underlying connection recorded one or more shutdown errors in state.shutdown_errors.","commonSituations":"Underlying websocket task panicked or returned an error during close; multiple streams failed to end cleanly; cascading failures during teardown after a network drop.","solutions":["Read each '; '-separated segment of the message — each is an individual shutdown error; address root causes individually","Check whether the shard's forwarder task exited with an unexpected error (e.g. network reset) and add retry/backoff for reconnects","Ensure tasks are awaited/joined properly on close so errors are not induced by premature drops","If errors are benign teardown noise (e.g. connection closed by peer), filter or log-and-continue upstream rather than failing"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = pool.close_shard(id, shard).await {\n    for err in e.to_string().split(\"; \") {\n        log::error!(\"shard shutdown error: {err}\");\n    }\n    // decide: fail hard, or continue teardown\n}","preventionTips":["Parse the '; '-joined message into individual errors for triage","Gracefully stop shard tasks before close so few shutdown errors accumulate","Treat peer-initiated disconnects during teardown as benign and filter them","Log full error chains ({e:#}) to preserve context"],"tags":["polymarket","websocket","shutdown","error-aggregation"],"backgroundTag":"shutdown-failure","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}