{"record":{"id":"7b6c68d3ba979fe5","repo":"nautechsystems/nautilus_trader","slug":"failed-to-get-block-info-for-chain","errorCode":null,"errorMessage":"Failed to get block info for chain {}: {}","messagePattern":"Failed to get block info for chain (.+?): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":430,"sourceCode":"    /// Returns an error if the database query fails.\n    pub async fn get_block_consistency_status(\n        &self,\n        chain: &Chain,\n    ) -> anyhow::Result<CachedBlocksConsistencyStatus> {\n        log::debug!(\"Fetching block consistency status\");\n\n        let result: (i64, i64) = sqlx::query_as(\n            \"\n            SELECT\n                COALESCE((SELECT number FROM block WHERE chain_id = $1 ORDER BY number DESC LIMIT 1), 0) as max_block,\n                get_last_continuous_block($1) as last_continuous_block\n            \"\n        )\n        .bind(chain.chain_id as i32)\n        .fetch_one(&self.pool)\n        .await\n        .map_err(|e| {\n            anyhow::anyhow!(\n                \"Failed to get block info for chain {}: {}\",\n                chain.chain_id,\n                e\n            )\n        })?;\n\n        Ok(CachedBlocksConsistencyStatus::new(\n            result.0 as u64,\n            result.1 as u64,\n        ))\n    }\n\n    /// Inserts or updates a block record in the database.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the database operation fails.\n    pub async fn add_block(&self, chain_id: u32, block: &Block) -> anyhow::Result<()> {","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L412-L448","documentation":"This error is raised when the query fetching the chain's cached block info (e.g. latest block number/timestamp used as the sync watermark) fails or the sqlx fetch_one errors. Note fetch_one also errors when zero rows are returned, so an unseeded/empty chain state also produces this message.","triggerScenarios":"Calling the get-block-info method for a chain when the row is missing (chain never synced) or the SELECT fails (connection, permissions, missing table/partition).","commonSituations":"Pointing the adapter at a fresh database where the chain has no cached blocks; wrong DATABASE_URL/environment; sqlx row-type mismatch after a schema change.","solutions":["Check the {e} source: QueryReturnedNoRows means the chain has no cached block info yet — seed or sync the chain first","Verify migrations/partitions exist for this chain_id","Confirm connection settings and that the correct database is targeted","Handle the empty case explicitly in the caller if starting from scratch is expected"],"exampleFix":"// before: treats empty cache as hard failure\nlet info = db.get_block_info(&chain).await?;\n// after: fall back to a starting block when nothing is cached\nlet info = match db.get_block_info(&chain).await {\n    Ok(info) => info,\n    Err(e) if is_empty_result(&e) => BlockInfo::default_start(chain),\n    Err(e) => return Err(e.into()),\n};","handlingStrategy":"fallback","validationCode":"// check the chain has cached state before reading block info\nlet has_row: (i64,) = sqlx::query_as(\n    \"SELECT COUNT(*) FROM block WHERE chain_id = $1\"\n).bind(chain.chain_id as i32).fetch_one(&pool).await?;\nlet cache_populated = has_row.0 > 0;","typeGuard":null,"tryCatchPattern":"let start = match db.get_block_info(&chain).await {\n    Ok(info) => info.next_block(),\n    Err(e) if is_query_returned_no_rows(&e) => chain.start_block(), // fresh cache\n    Err(e) => return Err(e.into()),\n};","preventionTips":["Seed the chain row and run an initial sync before querying cached block info","Distinguish empty-cache (QueryReturnedNoRows) from real query errors via the error source","Confirm the correct DATABASE_URL / environment when seeing this on startup","Handle first-run against a fresh database as a normal, expected path"],"tags":["database","postgres","sqlx","read"],"backgroundTag":"record-not-found","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"}