{"record":{"id":"62c0498c28cea950","repo":"nautechsystems/nautilus_trader","slug":"failed-to-register-blockchain-process-task-e","errorCode":null,"errorMessage":"Failed to register blockchain process task: {e}","messagePattern":"Failed to register blockchain process task: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/data/client.rs","lineNumber":249,"sourceCode":"                                    &mut core_client,\n                                    &mut pending_pool_messages,\n                                )\n                                .await;\n                            }\n                            Err(e) => {\n                                log::error!(\"Error processing RPC message: {e}\");\n                            }\n                        }\n                    }\n                }\n            }\n\n            log::debug!(\"Stopped task 'process'\");\n        };\n\n        self.session_tasks\n            .spawn(future)\n            .map_err(|e| anyhow::anyhow!(\"Failed to register blockchain process task: {e}\"))?;\n        Ok(startup_rx)\n    }\n\n    async fn process_live_blockchain_message(\n        msg: BlockchainMessage,\n        core_client: &mut BlockchainDataClientCore,\n        pending_pool_messages: &mut VecDeque<BlockchainMessage>,\n    ) {\n        let is_block = matches!(&msg, BlockchainMessage::Block(_));\n        let Some(msg) =\n            Self::ready_live_blockchain_message(msg, &core_client.cache, pending_pool_messages)\n        else {\n            return;\n        };\n\n        if let Some(data) = Self::data_event_from_blockchain_message(msg, core_client).await {\n            core_client.send_data(data);\n        }","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/data/client.rs#L231-L267","documentation":"This error is thrown when the tokio runtime refuses to spawn the background task that processes live blockchain messages after a WebSocket connect. `session_tasks.spawn(future)` returns an `JoinError`/spawn failure (most commonly the tokio runtime being shut down, which panics inside `tokio::spawn` semantics surfaced through the task set, or the task set being closed). The client wraps that failure in anyhow with this message and aborts the connect.","triggerScenarios":"Calling `connect()` on BlockchainDataClient when the enclosing tokio runtime is being shut down, when the `session_tasks` TaskSet/JoinSet has already been closed or aborted, or when the runtime lacks a reactor/worker context (e.g. spawn attempted outside a multi-threaded runtime with blocking workers).","commonSituations":"Applications shutting down their tokio runtime while the data client still tries to (re)connect; calling connect() from a blocking context or a runtime that is being dropped; a panic in the spawned future causing the task set to be closed; embedding the client in a runtime with `enable_time` only (no I/O driver).","solutions":["Ensure connect()/spawn_process_task runs inside a live multi-threaded tokio runtime and that the runtime is not being dropped or shut down during connect.","Check whether a prior task in `session_tasks` panicked or was aborted, closing the task set; fix the underlying panic or re-create the client instead of reusing it after shutdown.","If the client reconnects during teardown, guard the reconnect so it is cancelled when the runtime is shutting down (e.g. check a shutdown token before connect).","Log the inner JoinError (`{e}`) for details — it names whether the spawn failed because the runtime was gone or the task was cancelled."],"exampleFix":"// before: runtime shutting down mid-connect\nclient.connect().await?;\n// after: ensure shutdown completes before reconnecting\nif shutdown_token.is_cancelled() { return Ok(()); }\nruntime_handle.clone().spawn(async move { client.connect().await })\n    .await\n    .map_err(|e| anyhow::anyhow!(\"Failed to register blockchain process task: {e}\"))??;","handlingStrategy":"try-catch","validationCode":"// Rust: verify we are inside a live runtime before connecting\nassert!(tokio::runtime::Handle::try_current().is_ok(), \"connect() requires a live tokio runtime\");","typeGuard":null,"tryCatchPattern":"match client.connect().await {\n    Ok(rx) => { /* use startup_rx */ }\n    Err(e) if e.to_string().contains(\"Failed to register blockchain process task\") => {\n        log::warn!(\"Runtime shutting down; skipping blockchain client connect: {e}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep the tokio runtime alive for the entire lifetime of the client; shut down the client before dropping the runtime.","Do not call connect() from blocking contexts or runtimes without an I/O driver.","Fix panics in background tasks promptly — a panicked task can poison the session task set.","Gate reconnection logic on a shutdown token so teardown does not race with connect()."],"tags":["tokio","task-spawn","runtime-shutdown","rust"],"backgroundTag":"invalid-state-transition","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"}