{"record":{"id":"0ed601ac0fc3aff3","repo":"nautechsystems/nautilus_trader","slug":"fetched-block-while-requesting-rpc-snapshot-blo","errorCode":null,"errorMessage":"Fetched block {} while requesting RPC snapshot block {}","messagePattern":"Fetched block (.+?) while requesting RPC snapshot block (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/data/core.rs","lineNumber":2300,"sourceCode":"        let block = blocks_stream\n            .next()\n            .await\n            .with_context(|| format!(\"failed to fetch block {block_number} for RPC snapshot\"))?;\n\n        let block_position =\n            Self::block_scoped_snapshot_position_from_block(&mut self.cache, &block, block_number)?;\n        self.cache.add_pool_event_blocks_batch(vec![block]).await?;\n\n        Ok(block_position)\n    }\n\n    fn block_scoped_snapshot_position_from_block(\n        cache: &mut BlockchainCache,\n        block: &Block,\n        block_number: u64,\n    ) -> anyhow::Result<BlockPosition> {\n        if block.number != block_number {\n            anyhow::bail!(\n                \"Fetched block {} while requesting RPC snapshot block {}\",\n                block.number,\n                block_number\n            );\n        }\n\n        cache.cache_block_metadata(block);\n\n        Ok(BlockPosition::new(\n            block.number,\n            block.hash.clone(),\n            BLOCK_SCOPED_SNAPSHOT_INDEX,\n            BLOCK_SCOPED_SNAPSHOT_INDEX,\n        )\n        .with_block_hash(Some(block.hash.clone())))\n    }\n\n    /// Replays historical events for a pool to hydrate its profiler state.","sourceCodeStart":2282,"sourceCodeEnd":2318,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/data/core.rs#L2282-L2318","documentation":"block_scoped_snapshot_position_from_block checks that the Block object it received has the same number as the block_number that was requested when building an RPC snapshot. A mismatch means the caller fetched (or was handed) the wrong block for the requested snapshot position. The library bails to prevent constructing a BlockPosition from inconsistent data.","triggerScenarios":"Calling the snapshot-position code path when block.number != block_number — typically after a helper returns a 'latest' block that has advanced past the requested number, or a caller passes a cached block from an earlier fetch alongside a newer block number.","commonSituations":"Race with block production: the node advanced between requesting the block number and fetching its body; a stale cached Block object reused with a fresh block_number; a reorg replacing the block at that height; passing block.number from a log instead of the snapshot request block.","solutions":["Fetch the block and the snapshot in one atomic request at a pinned block number or hash","Assert block equality immediately after fetching and retry with a fresh fetch on mismatch","Use block hashes instead of numbers to be reorg-safe","Avoid reusing cached Block objects across snapshot requests","Serialize snapshot construction so no cache invalidation can swap the block mid-flight"],"exampleFix":"// before: reusing possibly stale block\nlet block = cache.get_cached_block();\nlet position = block_scoped_snapshot_position_from_block(&mut cache, &block, requested_number)?;\n// after: refetch the exact block requested\nlet block = client.fetch_block(requested_number).await?;\nlet position = block_scoped_snapshot_position_from_block(&mut cache, &block, requested_number)?;","handlingStrategy":"validation","validationCode":"if block.number != block_number {\n    return Err(anyhow!(\"block mismatch: got {}, wanted {}\", block.number, block_number));\n}","typeGuard":"fn is_requested_block(block: &Block, n: u64) -> bool { block.number == n }","tryCatchPattern":"match build_snapshot_position(&mut cache, &block, n) {\n    Ok(pos) => pos,\n    Err(e) if e.to_string().contains(\"Fetched block\") => retry_with_fresh_fetch(n).await?,\n    Err(e) => return Err(e),\n}","preventionTips":["Fetch block body and snapshot atomically at a pinned block","Do not reuse cached Block objects across snapshot requests","Prefer block hashes to be reorg-safe"],"tags":["rpc","consistency","blockchain","block","snapshot"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}