nautechsystems/nautilus_trader · error

std::mem::take(&mut self.shutdown_errors).join("; ")

Error message

std::mem::take(&mut self.shutdown_errors).join("; ")

What it means

teardown_partial_connect on the Coinbase data client accumulates any errors encountered while disconnecting the WebSocket (and other partial-connect teardown steps) into shutdown_errors, then fails the teardown with all messages joined by '; '. This surfaces why a partially-connected client could not be cleanly rolled back.

Source

Thrown at crates/adapters/coinbase/src/data/mod.rs:334

        let (tasks_result, polls_result) =
            tokio::join!(self.finish_tasks(), self.deriv_polls.finish_shutdown());

        if let Err(e) = tasks_result {
            self.shutdown_errors.push(e.to_string());
        }

        if let Err(e) = polls_result {
            self.shutdown_errors.push(e.to_string());
        }

        if let Err(e) = self.ws_client.disconnect().await {
            self.shutdown_errors.push(e.to_string());
        }
        self.is_connected.store(false, Ordering::Relaxed);

        if !self.shutdown_errors.is_empty() {
            anyhow::bail!(std::mem::take(&mut self.shutdown_errors).join("; "));
        }
        Ok(())
    }

    fn product_id(instrument_id: InstrumentId) -> Ustr {
        instrument_id.symbol.inner()
    }

    // Resolves a caller-supplied product id to Coinbase's canonical alias (if
    // any). Coinbase consolidates aliased pairs into a single book server-side
    // and rewrites WS subscription confirmations and inbound messages to use
    // the canonical id (e.g. BTC-USDC -> BTC-USD), so we must subscribe with
    // the canonical id and remember the mapping so inbound messages can be
    // re-keyed to what the strategy actually subscribed to.
    fn resolve_wire_product_id(&self, subscribed: Ustr) -> Ustr {
        self.http_client
            .product_aliases()
            .get_cloned(&subscribed)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the joined message to identify which teardown step(s) failed (usually the WS disconnect)
  2. Retry disconnect() once after a short delay; the socket may already be half-closed
  3. Recreate the client if teardown repeatedly fails — state may be inconsistent after partial connect
  4. Fix the root cause of the original partial connect that triggered the rollback
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the client is connected before disconnect
if client.is_connected() { client.disconnect().await?; }

Try / catch

if let Err(e) = client.disconnect().await {
    log::warn!("coinbase teardown failed: {e}; recreating client");
    client = rebuild_client().await;
}

Prevention

When it happens

Trigger: A connect() step fails partway and the rollback path calls ws_client.disconnect().await which itself errors (e.g. socket already closed, network gone), leaving non-empty shutdown_errors.

Common situations: Network drop during a failed connect; calling disconnect() on a client whose WS is already dead; concurrent teardowns racing on the same client.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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