{"record":{"id":"94c9b5aa463d06b7","repo":"nautechsystems/nautilus_trader","slug":"cannot-advance-rpc-profiler-from-block-to-earli","errorCode":null,"errorMessage":"cannot advance RPC profiler from block {} to earlier block {to_block}","messagePattern":"cannot advance RPC profiler from block (.+?) to earlier block (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/data/core.rs","lineNumber":1613,"sourceCode":"    /// The profiler must come from [`Self::bootstrap_pool_profiler_from_rpc_snapshot`] or an earlier\n    /// call to this method. This keeps one command incremental without trusting an unproven stored\n    /// snapshot as the topology source.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the profiler has no RPC snapshot watermark, the target precedes that\n    /// watermark, event streaming fails, or RPC hydration fails.\n    pub async fn advance_pool_profiler_from_rpc_snapshot(\n        &mut self,\n        profiler: PoolProfiler,\n        to_block: u64,\n    ) -> anyhow::Result<(PoolProfiler, bool)> {\n        let from_position = profiler.last_processed_event.clone().ok_or_else(|| {\n            anyhow::anyhow!(\"cannot advance an RPC profiler without a snapshot watermark\")\n        })?;\n\n        if to_block < from_position.number {\n            anyhow::bail!(\n                \"cannot advance RPC profiler from block {} to earlier block {to_block}\",\n                from_position.number\n            );\n        }\n\n        self.construct_pool_profiler_from_hypersync_rpc(profiler, Some(from_position), to_block)\n            .await\n    }\n\n    async fn seed_pool_profiler_from_latest_snapshot(\n        &self,\n        pool: &SharedPool,\n        to_block: u64,\n    ) -> anyhow::Result<(PoolProfiler, Option<BlockPosition>)> {\n        let mut profiler = PoolProfiler::new(pool.clone());\n\n        let from_position = match self\n            .cache","sourceCodeStart":1595,"sourceCodeEnd":1631,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/data/core.rs#L1595-L1631","documentation":"advance_pool_profiler_from_rpc_snapshot moves a profiler forward from its last processed event watermark to to_block. If the requested to_block is earlier than the current watermark (from_position.number), time would go backwards, which the API forbids.","triggerScenarios":"Calling advance_pool_profiler_from_rpc_snapshot with to_block lower than profiler.last_processed_event.number, e.g. reusing a stale/older target block or mixing profilers across chains.","commonSituations":"Caching a to_block from a previous request and replaying it against an already-advanced profiler; concurrent callers advancing the same profiler with out-of-order blocks; recovering from a backup with an older target.","solutions":["Query the profiler's last_processed_event and request to_block >= that block number","If you truly need history before the watermark, rebuild a fresh profiler via bootstrap_pool_profiler_from_rpc_snapshot","Ensure only one caller advances a given profiler and targets are monotonic"],"exampleFix":"// before\nlet to_block = 19_000_000; // older than profiler watermark\nclient.advance_pool_profiler_from_rpc_snapshot(profiler, to_block).await?;\n// after\nlet to_block = profiler.last_processed_event.as_ref().unwrap().number.max(19_000_000);\nclient.advance_pool_profiler_from_rpc_snapshot(profiler, to_block).await?;","handlingStrategy":"validation","validationCode":"let from = profiler.last_processed_event.as_ref().map(|p| p.number).unwrap_or(0);\nassert!(to_block >= from, \"to_block {to_block} precedes watermark {from}\");\nclient.advance_pool_profiler_from_rpc_snapshot(profiler, to_block).await?;","typeGuard":"fn can_advance(p: &PoolProfiler, to_block: u64) -> bool {\n    p.last_processed_event.as_ref().is_some_and(|w| to_block >= w.number)\n}","tryCatchPattern":"match client.advance_pool_profiler_from_rpc_snapshot(profiler, to_block).await {\n    Err(e) if e.to_string().contains(\"to earlier block\") => {\n        log::warn!(\"profiler already beyond {to_block}; nothing to do\");\n        Ok((profiler.clone(), false))\n    }\n    r => r,\n}","preventionTips":["Always read last_processed_event before choosing to_block","Make advance calls monotonic per profiler (single owner)","Never reuse cached to_block values across profiler instances"],"tags":["profiler","blocks","argument-range","monotonic"],"backgroundTag":"argument-out-of-range","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"}