{"record":{"id":"38a2a59da004e491","repo":"nautechsystems/nautilus_trader","slug":"failed-tx-channel-e","errorCode":null,"errorMessage":"{FAILED_TX_CHANNEL}: {e}","messagePattern":"\\{FAILED_TX_CHANNEL\\}: \\{e\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/redis/cache.rs","lineNumber":425,"sourceCode":"        }\n    }\n\n    /// Sends a flush command through the background task channel and blocks\n    /// until it completes. Safe to call from any runtime context.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the command channel is closed or the reply is lost.\n    pub fn flushdb_sync(&self) -> anyhow::Result<()> {\n        let (reply_tx, reply_rx) = mpsc::sync_channel(1);\n        let cmd = DatabaseCommand {\n            op_type: DatabaseOperation::Flush(reply_tx),\n            key: None,\n            payload: None,\n        };\n        self.tx\n            .send(cmd)\n            .map_err(|e| anyhow::anyhow!(\"{FAILED_TX_CHANNEL}: {e}\"))?;\n        blocking_recv(&reply_rx).map_err(|e| anyhow::anyhow!(\"Failed to flush database: {e}\"))?;\n        Ok(())\n    }\n\n    /// Retrieves all keys matching the given `pattern` from Redis for this trader.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the underlying Redis scan operation fails.\n    pub async fn keys(&mut self, pattern: &str) -> anyhow::Result<Vec<String>> {\n        let pattern = format!(\"{}{REDIS_DELIMITER}{pattern}\", self.trader_key);\n        DatabaseQueries::scan_keys(&mut self.con, pattern).await\n    }\n\n    /// Reads the value(s) associated with `key` for this trader from Redis.\n    ///\n    /// # Errors\n    ///","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/redis/cache.rs#L407-L443","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Recreate the RedisCache/client so the background task is restarted","Check logs for the background task's panic or disconnect reason before this error","Verify the Redis server is reachable and the connection task is alive before flushing","Restructure shutdown so flushdb is called before the cache is dropped"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// check cache health before flushing\nif cache.is_closed() {\n    anyhow::bail!(\"cache background task is not running; recreate the cache before flush\");\n}","typeGuard":null,"tryCatchPattern":"match cache.flushdb_sync() {\n    Ok(()) => log::info!(\"redis db flushed\"),\n    Err(e) if e.to_string().contains(FAILED_TX_CHANNEL) => {\n        log::error!(\"redis background task dead: {e:#}; recreating cache\");\n        cache = RedisCache::new(...)?;\n        cache.flushdb_sync()?;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep the background task alive for the cache's full lifetime","Log and handle background task panics/disconnects immediately","Flush before shutting down the cache, not after"],"tags":["redis","channel-closed","shutdown"],"backgroundTag":"broken-pipe","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}