nautechsystems/nautilus_trader · error · anyhow::Error
Missing dex_name for pool snapshot {}
Error message
Missing dex_name for pool snapshot {} What it means
The snapshot row has a NULL `dex_name` column, but a DEX name is mandatory to resolve the chain's DEX registry entry and build the pool instrument. The library treats a snapshot without a DEX name as corrupt/incomplete and refuses to load it.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:2533
transaction_index,
log_index,
)
.await?;
let ticks = self
.load_pool_ticks_for_snapshot(
chain_id,
pool_identifier,
block,
transaction_index,
log_index,
)
.await?;
let dex_name = row
.try_get::<Option<String>, _>("dex_name")?
.ok_or_else(|| {
anyhow::anyhow!("Missing dex_name for pool snapshot {}", pool_identifier)
})?;
let chain = Chain::from_chain_id(chain_id)
.ok_or_else(|| anyhow::anyhow!("Unknown chain_id: {chain_id}"))?;
let dex_type = DexType::from_dex_name(&dex_name)
.ok_or_else(|| anyhow::anyhow!("Unknown dex_name: {dex_name}"))?;
let dex_extended = crate::exchanges::get_dex_extended(chain.name, &dex_type)
.ok_or_else(|| {
anyhow::anyhow!("No DEX extended found for {} on {}", dex_name, chain.name)
})?;
let instrument_id =
Pool::create_instrument_id(chain.name, &dex_extended.dex, pool_identifier.as_ref());
Ok(Some(PoolSnapshot::new(
instrument_id,
state,View on GitHub (pinned to 18893faf8b)
Solutions
- Backfill `dex_name` for existing rows from pool metadata (or delete affected snapshots and re-snapshot).
- Add a NOT NULL constraint on `dex_name` so bad rows are rejected at write time.
- Ensure the snapshot writer always records `dex_name` before INSERT (unit-test the persist path).
- If rows came from an import/ETL job, fix the job to include dex_name and re-run.
Example fix
// schema // before: dex_name TEXT // after ALTER TABLE pool_snapshots ALTER COLUMN dex_name SET NOT NULL;
Defensive patterns
Strategy: validation
Validate before calling
let dex: Option<String> = sqlx::query_scalar(
"SELECT dex_name FROM pool_snapshots WHERE pool_identifier = $1 ORDER BY block DESC LIMIT 1")
.bind(pool_id).fetch_optional(&db).await?;
if dex.as_deref().unwrap_or_default().is_empty() {
return Err("snapshot missing dex_name; backfill or re-snapshot");
} Try / catch
match load_snapshot(...).await {
Err(e) if e.to_string().contains("Missing dex_name") => {
tracing::warn!("corrupt snapshot row, re-snapshotting");
re_snapshot(pool_id).await
}
other => other,
} Prevention
- Enforce NOT NULL on dex_name at the schema level.
- Backfill required columns right after adding them in a migration.
- Validate rows after any DB import/ETL before the adapter reads them.
When it happens
Trigger: Loading a pool snapshot row where `dex_name` is NULL — rows written before the column existed, partially written rows, manual inserts, or a writer path that failed to record the DEX name.
Common situations: Pre-migration legacy snapshot rows lacking the newly added `dex_name` column; manual DB seeding during testing; partial writes from an interrupted persistence job.
Related errors
- Missing block timestamp for pool snapshot {} at block {}
- Execution payload {} has no envelope during rewrap
- Duplicate fill event for position {position_id}: {}
- Failed to load latest valid pool snapshot: {e}
- Invalid block timestamp '{block_timestamp}': {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/17b867c00e9619c8.
Report an issue: GitHub.