{"record":{"id":"b861b5e4f2c9848e","repo":"nautechsystems/nautilus_trader","slug":"failed-to-send-query-add-quote-to-database-message","errorCode":null,"errorMessage":"Failed to send query add_quote to database message handler: {e}","messagePattern":"Failed to send query add_quote to database message handler: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/cache.rs","lineNumber":988,"sourceCode":"    }\n\n    fn add_position_snapshot(&self, snapshot: &PositionSnapshot) -> anyhow::Result<()> {\n        let query = DatabaseQuery::AddPositionSnapshot(snapshot.to_owned());\n        self.tx.send(query).map_err(|e| {\n            anyhow::anyhow!(\n                \"Failed to send query add_position_snapshot to database message handler: {e}\"\n            )\n        })\n    }\n\n    fn add_order_book(&self, _order_book: &OrderBook) -> anyhow::Result<()> {\n        todo!()\n    }\n\n    fn add_quote(&self, quote: &QuoteTick) -> anyhow::Result<()> {\n        let query = DatabaseQuery::AddQuote(quote.to_owned());\n        self.tx.send(query).map_err(|e| {\n            anyhow::anyhow!(\"Failed to send query add_quote to database message handler: {e}\")\n        })\n    }\n\n    fn load_quotes(&self, instrument_id: &InstrumentId) -> anyhow::Result<Vec<QuoteTick>> {\n        let pool = self.pool.clone();\n        let instrument_id = instrument_id.to_owned();\n        let (tx, rx) = std::sync::mpsc::channel();\n\n        tokio::spawn(async move {\n            let result = DatabaseQueries::load_quotes(&pool, &instrument_id).await;\n            match result {\n                Ok(quotes) => {\n                    if let Err(e) = tx.send(quotes) {\n                        log::error!(\"Failed to send quotes for instrument {instrument_id}: {e:?}\");\n                    }\n                }\n                Err(e) => {\n                    log::error!(\"Failed to load quotes for instrument {instrument_id}: {e:?}\");","sourceCodeStart":970,"sourceCodeEnd":1006,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/sql/cache.rs#L970-L1006","documentation":"The PostgreSQL cache adapter writes are asynchronous: add_quote wraps the QuoteTick in a DatabaseQuery::AddQuote and sends it over an mpsc channel (self.tx) to a background database message handler task. This error is raised when that send fails, which only happens if the receiver half held by the handler task has been dropped — i.e. the background writer task has shut down or was never started. The tick itself is fine; the failure is in the cache's internal messaging plumbing.","triggerScenarios":"Calling add_quote (directly from Rust or via py_add_quote from Python) after the database message handler task has exited, e.g. the connection pool/task was aborted, the cache was shut down, or the handler task panicked on startup.","commonSituations":"Closing or dropping the cache/database adapter while a live strategy or script still writes quotes; a startup failure of the message handler (bad DB config) leaving the receiver dropped; holding a stale cache instance after disconnect during a long-running backtest/live session.","solutions":["Verify the PostgreSQL cache adapter is fully started and its background handler task is alive before writing quotes","Recreate or restart the cache/database adapter if it was shut down, instead of reusing the old instance","Check handler task logs for a panic or early exit (e.g. failed pool connection) and fix the underlying startup cause","If writes are optional, catch the anyhow error from add_quote and degrade gracefully rather than crashing the strategy"],"exampleFix":"// before: writing through a stale adapter after shutdown\ncache.add_quote(&quote)?;\n// after: rebuild the adapter when the handler channel is closed\nif let Err(e) = cache.add_quote(&quote) {\n    if e.to_string().contains(\"Failed to send query add_quote\") {\n        cache = CacheDatabaseAdapter::new(config)?; // restart handler task\n        cache.add_quote(&quote)?;\n    } else { return Err(e); }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Python\ntry:\n    cache.add_quote(quote)\nexcept Exception as e:\n    if \"Failed to send query add_quote\" in str(e):\n        logger.error(\"DB cache handler down; reinitializing adapter\")\n        cache = rebuild_cache_adapter()\n    else:\n        raise\n// Rust\nif let Err(e) = cache.add_quote(&quote) {\n    tracing::error!(\"quote persistence failed: {e:#}\");\n}","preventionTips":["Keep the database adapter alive for the entire lifetime of writers","Establish a single ownership/shutdown order: stop writers, then drop the cache","Monitor handler task health; restart the adapter if the task exits","Test shutdown paths so writes never race adapter teardown"],"tags":["rust","channel","database","postgres"],"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"}