nautechsystems/nautilus_trader · error

{FAILED_TX_CHANNEL}: {e}

Error message

{FAILED_TX_CHANNEL}: {e}

What it means

Raised by RedisCache::flushdb_sync when the command channel (self.tx) to the background Redis task is closed, so sending the Flush command fails. This means the cache's background writer task has terminated and no Redis operation can be delivered.

Source

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

        }
    }

    /// Sends a flush command through the background task channel and blocks
    /// until it completes. Safe to call from any runtime context.
    ///
    /// # Errors
    ///
    /// Returns an error if the command channel is closed or the reply is lost.
    pub fn flushdb_sync(&self) -> anyhow::Result<()> {
        let (reply_tx, reply_rx) = mpsc::sync_channel(1);
        let cmd = DatabaseCommand {
            op_type: DatabaseOperation::Flush(reply_tx),
            key: None,
            payload: None,
        };
        self.tx
            .send(cmd)
            .map_err(|e| anyhow::anyhow!("{FAILED_TX_CHANNEL}: {e}"))?;
        blocking_recv(&reply_rx).map_err(|e| anyhow::anyhow!("Failed to flush database: {e}"))?;
        Ok(())
    }

    /// Retrieves all keys matching the given `pattern` from Redis for this trader.
    ///
    /// # Errors
    ///
    /// Returns an error if the underlying Redis scan operation fails.
    pub async fn keys(&mut self, pattern: &str) -> anyhow::Result<Vec<String>> {
        let pattern = format!("{}{REDIS_DELIMITER}{pattern}", self.trader_key);
        DatabaseQueries::scan_keys(&mut self.con, pattern).await
    }

    /// Reads the value(s) associated with `key` for this trader from Redis.
    ///
    /// # Errors
    ///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Recreate the RedisCache/client so the background task is restarted
  2. Check logs for the background task's panic or disconnect reason before this error
  3. Verify the Redis server is reachable and the connection task is alive before flushing
  4. Restructure shutdown so flushdb is called before the cache is dropped
Defensive patterns

Strategy: try-catch

Validate before calling

// check cache health before flushing
if cache.is_closed() {
    anyhow::bail!("cache background task is not running; recreate the cache before flush");
}

Try / catch

match cache.flushdb_sync() {
    Ok(()) => log::info!("redis db flushed"),
    Err(e) if e.to_string().contains(FAILED_TX_CHANNEL) => {
        log::error!("redis background task dead: {e:#}; recreating cache");
        cache = RedisCache::new(...)?;
        cache.flushdb_sync()?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling flushdb_sync after the background task backing the cache has exited (task panicked, Redis connection task dropped, or cache was torn down) so mpsc::send returns Err.

Common situations: Calling flush on a cache whose client disconnected (Redis server restart) and the worker gave up, using a cache instance after shutdown in tests or process teardown, or a panic inside the background task.

Related errors


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