nautechsystems/nautilus_trader · error

load_index_order_position channel closed: {e}

Error message

load_index_order_position channel closed: {e}

What it means

Loads the (index_order → position) mapping from Redis via a blocking worker thread and an mpsc result channel. This error indicates the channel closed before a result arrived — the worker task was dropped or panicked, so `blocking_recv` returned `RecvError`.

Source

Thrown at crates/infrastructure/src/redis/cache.rs:1488

            self.encoding(),
        )
        .await
    }

    fn load_index_order_position(&self) -> anyhow::Result<AHashMap<ClientOrderId, PositionId>> {
        let con = self.database.con.clone();
        let trader_key = self.database.trader_key.clone();
        let (tx, rx) = mpsc::channel();

        get_runtime().spawn(async move {
            let result = DatabaseQueries::load_index_order_position(&con, &trader_key).await;
            if let Err(e) = tx.send(result) {
                log::error!("Failed to send load_index_order_position result: {e:?}");
            }
        });

        blocking_recv(&rx)
            .map_err(|e| anyhow::anyhow!("load_index_order_position channel closed: {e}"))?
    }

    fn load_index_order_client(&self) -> anyhow::Result<AHashMap<ClientOrderId, ClientId>> {
        let con = self.database.con.clone();
        let trader_key = self.database.trader_key.clone();
        let (tx, rx) = mpsc::channel();

        get_runtime().spawn(async move {
            let result = DatabaseQueries::load_index_order_client(&con, &trader_key).await;
            if let Err(e) = tx.send(result) {
                log::error!("Failed to send load_index_order_client result: {e:?}");
            }
        });

        blocking_recv(&rx)
            .map_err(|e| anyhow::anyhow!("load_index_order_client channel closed: {e}"))?
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Look for a preceding log entry ('Failed to send load_index_order_position result' or a panic) to identify the root cause
  2. Inspect the Redis keys under the trader's index_order_position prefix for malformed or missing entries and repair/remove them
  3. Retry the load on a healthy connection
  4. If reproducible, refactor the task to propagate the error through the channel instead of logging it
Defensive patterns

Strategy: retry

Validate before calling

// verify index data shape before load
let raw: Option<String> = redis::cmd("GET")
    .arg(format!("{trader_key}:index_order_position"))
    .query(&mut con)?;
assert!(raw.is_some(), "index_order_position key missing");

Try / catch

// Rust
match cache.load_index_order_position() {
    Ok(index) => index,
    Err(e) if e.to_string().contains("channel closed") => {
        log::error!("index loader task died: {e:#}");
        cache.load_index_order_position()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the order/position index load during cache reconstruction when the spawned index-loading task panics (bad payload, missing key structure) or is dropped before sending its result.

Common situations: Partially written or manually edited Redis index keys; corrupted msgpack/json data in the index collection; process shutdown mid-load.

Related errors


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