nautechsystems/nautilus_trader · critical
database presence is checked by caller
Error message
database presence is checked by caller
What it means
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.
Source
Thrown at crates/adapters/blockchain/src/data/core.rs:1634
);
}
self.construct_pool_profiler_from_hypersync_rpc(profiler, Some(from_position), to_block)
.await
}
async fn seed_pool_profiler_from_latest_snapshot(
&self,
pool: &SharedPool,
to_block: u64,
) -> anyhow::Result<(PoolProfiler, Option<BlockPosition>)> {
let mut profiler = PoolProfiler::new(pool.clone());
let from_position = match self
.cache
.database
.as_ref()
.expect("database presence is checked by caller")
.load_latest_pool_snapshot(
pool.chain.chain_id,
&pool.pool_identifier,
Some(to_block),
true,
)
.await
{
Ok(Some(snapshot)) => {
// Empty snapshots at the pool's creation block are stubs left behind by an
// earlier bootstrap that bailed before any liquidity events landed. Restoring
// marks the profiler as initialized, which then conflicts with the Initialize
// event that hypersync re-emits at the same block. Fall through to a fresh
// bootstrap rather than trust the stub.
if snapshot.positions.is_empty()
&& snapshot.ticks.is_empty()
&& snapshot.block_position.number == pool.creation_block
{View on GitHub (pinned to 18893faf8b)
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.
Example fix
// before
let snapshot = self.cache.database.as_ref().expect("database presence is checked by caller")
.load_latest_pool_snapshot(...)?;
// after
let database = self.cache.database.as_ref().ok_or_else(|| {
anyhow::anyhow!("database not configured in cache; cannot seed pool profiler")
})?;
let snapshot = database.load_latest_pool_snapshot(...)?; Defensive patterns
Strategy: validation
Validate before calling
if engine.cache.database.is_none() {
anyhow::bail!("cache has no database configured; cannot bootstrap pool profiler");
}
engine.bootstrap_latest_pool_profiler(&pool, to_block)?; Type guard
fn has_database(cache: &Cache) -> bool {
cache.database.is_some()
} Try / catch
// Rust panics are not catchable via Result; use std::panic::catch_unwind only as a last resort.
let result = std::panic::catch_unwind(|| engine.bootstrap_latest_pool_profiler(&pool, to_block));
match result {
Ok(inner) => inner?,
Err(_) => anyhow::bail!("panic in profiler bootstrap: database not configured"),
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Profiler should have last_processed_event
- in-flight mutex poisoned
- wallet balance mutex poisoned
- instrument update lock poisoned
- rate limiter decision lock poisoned
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f0479ab2a9685066.
Report an issue: GitHub.