{"record":{"id":"f0479ab2a9685066","repo":"nautechsystems/nautilus_trader","slug":"database-presence-is-checked-by-caller","errorCode":null,"errorMessage":"database presence is checked by caller","messagePattern":"database presence is checked by caller","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/data/core.rs","lineNumber":1634,"sourceCode":"            );\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\n            .database\n            .as_ref()\n            .expect(\"database presence is checked by caller\")\n            .load_latest_pool_snapshot(\n                pool.chain.chain_id,\n                &pool.pool_identifier,\n                Some(to_block),\n                true,\n            )\n            .await\n        {\n            Ok(Some(snapshot)) => {\n                // Empty snapshots at the pool's creation block are stubs left behind by an\n                // earlier bootstrap that bailed before any liquidity events landed. Restoring\n                // marks the profiler as initialized, which then conflicts with the Initialize\n                // event that hypersync re-emits at the same block. Fall through to a fresh\n                // bootstrap rather than trust the stub.\n                if snapshot.positions.is_empty()\n                    && snapshot.ticks.is_empty()\n                    && snapshot.block_position.number == pool.creation_block\n                {","sourceCodeStart":1616,"sourceCodeEnd":1652,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/data/core.rs#L1616-L1652","documentation":"This is an internal invariant panic: seed_pool_profiler_from_latest_snapshot asserts via expect() that cache.database is Some before loading the latest pool snapshot. The function's contract requires callers (e.g. bootstrap_latest_pool_profiler) to have already verified that a database is configured. If the invariant is broken, the process panics instead of returning an error.","triggerScenarios":"Calling seed_pool_profiler_from_latest_snapshot (directly or via bootstrap_latest_pool_profiler) on a data engine whose cache was constructed with database: None, so cache.database.as_ref() yields None at crates/adapters/blockchain/src/data/core.rs:1634.","commonSituations":"Running the pool-profiler bootstrap path in a deployment or test harness where the cache was built without a database backend (e.g. no persistence configured, or a refactored constructor dropped the database argument); wiring a custom cache implementation that does not populate the database field.","solutions":["Configure the cache with a database before calling bootstrap_latest_pool_profiler / seed_pool_profiler_from_latest_snapshot.","Add an explicit guard in the caller (e.g. ensure cache.database.is_some(), otherwise construct a database or return an error) before invoking the seeder.","If you maintain this code, convert the expect into an anyhow::bail! or Option check so callers get a recoverable error instead of a panic."],"exampleFix":"// before\nlet snapshot = self.cache.database.as_ref().expect(\"database presence is checked by caller\")\n    .load_latest_pool_snapshot(...)?;\n// after\nlet database = self.cache.database.as_ref().ok_or_else(|| {\n    anyhow::anyhow!(\"database not configured in cache; cannot seed pool profiler\")\n})?;\nlet snapshot = database.load_latest_pool_snapshot(...)?;","handlingStrategy":"validation","validationCode":"if engine.cache.database.is_none() {\n    anyhow::bail!(\"cache has no database configured; cannot bootstrap pool profiler\");\n}\nengine.bootstrap_latest_pool_profiler(&pool, to_block)?;","typeGuard":"fn has_database(cache: &Cache) -> bool {\n    cache.database.is_some()\n}","tryCatchPattern":"// Rust panics are not catchable via Result; use std::panic::catch_unwind only as a last resort.\nlet result = std::panic::catch_unwind(|| engine.bootstrap_latest_pool_profiler(&pool, to_block));\nmatch result {\n    Ok(inner) => inner?,\n    Err(_) => anyhow::bail!(\"panic in profiler bootstrap: database not configured\"),\n}","preventionTips":["Always construct the cache with a database backend before enabling pool-profiler features.","Add a startup assertion/config check that persistence is configured when snapshot-based profiling is used.","Prefer explicit Result-returning APIs over expect() in new code paths that depend on optional cache fields."],"tags":["panic","invariant-violation","missing-database","rust"],"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"}