nautechsystems/nautilus_trader · error

errors.join("; ")

Error message

errors.join("; ")

What it means

During teardown of the Bybit data client, finish_tasks joins session and command tasks; any task that fails to finish is collected as a message. If any errors accumulated, the whole operation bails with all messages joined by "; ". This indicates background websocket/HTTP tasks did not shut down cleanly during connect/teardown.

Source

Thrown at crates/adapters/bybit/src/data.rs:264

        let (session_result, command_result) = tokio::join!(
            self.session_tasks
                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),
            self.command_tasks
                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2)),
        );
        let mut errors = Vec::new();
        if let Err(e) = session_result {
            errors.push(format!("failed to finish Bybit data session tasks: {e}"));
        }

        if let Err(e) = command_result {
            errors.push(format!("failed to finish Bybit data command tasks: {e}"));
        }

        if errors.is_empty() {
            Ok(())
        } else {
            anyhow::bail!(errors.join("; "))
        }
    }

    async fn prepare_task_groups(&mut self) -> anyhow::Result<()> {
        if !self.session_tasks.is_open() || !self.command_tasks.is_open() {
            self.teardown_partial_connect().await?;
            self.session_tasks
                .start_generation()
                .context("failed to start Bybit data session task generation")?;
            self.command_tasks
                .start_generation()
                .context("failed to start Bybit data command task generation")?;
            self.cancellation_token = self.session_tasks.cancellation_token();
        }
        Ok(())
    }

    fn spawn_ws<F>(&self, fut: F, context: &'static str)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the joined messages to identify which tasks failed and the root cause
  2. Check network/proxy stability and Bybit exchange status
  3. Retry the connection after the failed teardown
  4. If persistent, capture logs and file an issue with the specific task error
Defensive patterns

Strategy: try-catch

Validate before calling

// before connect: check connectivity to Bybit endpoints
async fn bybit_reachable() -> bool { reqwest::get("https://api.bybit.com/v5/market/time").await.is_ok() }

Try / catch

match client.connect().await {
    Ok(()) => {},
    Err(e) => {
        log::error!("Bybit data connect/teardown failed: {e:#}");
        tokio::time::sleep(BACKOFF).await;
        retry_connect();
    }
}

Prevention

When it happens

Trigger: Calling connect (via prepare_task_groups -> teardown_partial_connect) or disconnect when one or more spawned data command tasks returned an error like "failed to finish Bybit data command tasks: ...".

Common situations: Network drops mid-connect leaving tasks in a bad state; exchange websocket closing unexpectedly during startup/shutdown; partial connect failures where some tasks already errored.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/246feeaa5a0003ac. Report an issue: GitHub.