nautechsystems/nautilus_trader · error

TransactionManager not initialized - call connect() first

Error message

TransactionManager not initialized - call connect() first

What it means

The dYdX execution client keeps its TransactionManager (on-chain transaction construction/signing state) in an Option that is populated during connect(). get_execution_components() unwraps it with ok_or_else, so any order/cancel operation invoked before connect() completes (or after it failed to set the manager) throws this error. It is a lifecycle/state error, not a network error.

Source

Thrown at crates/adapters/dydx/src/execution/mod.rs:832

        if instrument.is_none() {
            self.instrument_cache.log_missing_clob_pair_id(clob_pair_id);
        }

        instrument
    }

    fn get_execution_components(
        &self,
    ) -> anyhow::Result<(
        Arc<TransactionManager>,
        Arc<TxBroadcaster>,
        Arc<OrderMessageBuilder>,
    )> {
        let tx_manager = self
            .tx_manager
            .as_ref()
            .ok_or_else(|| {
                anyhow::anyhow!("TransactionManager not initialized - call connect() first")
            })?
            .clone();
        let broadcaster = self
            .broadcaster
            .as_ref()
            .ok_or_else(|| anyhow::anyhow!("TxBroadcaster not initialized - call connect() first"))?
            .clone();
        let order_builder = self
            .order_builder
            .as_ref()
            .ok_or_else(|| {
                anyhow::anyhow!("OrderMessageBuilder not initialized - call connect() first")
            })?
            .clone();
        Ok((tx_manager, broadcaster, order_builder))
    }

    fn spawn_task<F>(&self, label: &'static str, fut: F)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure connect() is called and completes successfully before submitting or canceling orders
  2. Check logs/return value of connect() for earlier failures (RPC endpoint unreachable) that left the manager uninitialized
  3. Re-create or reconnect the execution client if the client entered a disconnected state

Example fix

// before
let client = DydxExecClient::new(config)?;
client.submit_order(order)?; // tx_manager still None
// after
let client = DydxExecClient::new(config)?;
client.connect().await?;
client.submit_order(order)?;
Defensive patterns

Strategy: try-catch

Validate before calling

// guard before trading calls
if !client.is_connected() {
    client.connect().await?;
}

Try / catch

match client.submit_order(order).await {
    Err(e) if e.to_string().contains("TransactionManager not initialized") => {
        client.connect().await?; // re-initialize, then retry once
        client.submit_order(order).await?;
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling submit_order, submit_order_list, cancel_order, cancel_all_orders, or batch_cancel_orders on a DydxExecClient whose connect() was never called, is still in progress, or failed before tx_manager was assigned.

Common situations: Submitting orders immediately after client construction without awaiting connection; connect() failed earlier (network/RPC error) leaving the Option as None; using the client before the node/gRPC endpoint is reachable; a reconnect dropped and never re-established the manager.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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