nautechsystems/nautilus_trader · error

Cannot extract snapshot: no events processed yet

Error message

Cannot extract snapshot: no events processed yet

What it means

`extract_snapshot` serializes the profiler's full state (positions, ticks, fee model) into a `PoolSnapshot` for checkpoint/restore. A snapshot includes `last_processed_event` so a restored profiler can resume replay correctly; if no event has ever been processed, there is no resume point, so the method errors instead of producing a snapshot with undefined provenance.

Source

Thrown at crates/model/src/defi/pool_analysis/profiler.rs:1882

    /// all liquidity positions, and the full tick distribution into a portable
    /// [`PoolSnapshot`] structure. This snapshot can be serialized, persisted
    /// to database, or used to restore pool state later.
    ///
    /// # Errors
    ///
    /// Returns an error if no events have been processed yet, since there is no event watermark to
    /// anchor the snapshot to.
    pub fn extract_snapshot(&self) -> anyhow::Result<PoolSnapshot> {
        let positions: Vec<_> = self.positions.values().cloned().collect();
        let ticks: Vec<_> = self.tick_map.get_all_ticks().values().copied().collect();

        let mut state = self.state.clone();
        state.liquidity = self.tick_map.liquidity;

        let last_processed_event = self
            .last_processed_event
            .clone()
            .ok_or_else(|| anyhow::anyhow!("Cannot extract snapshot: no events processed yet"))?;

        Ok(PoolSnapshot::new(
            self.pool.instrument_id,
            state,
            positions,
            ticks,
            self.analytics.clone(),
            last_processed_event,
            self.last_processed_ts.unwrap_or(self.pool.ts_init), // ts_event (last processed event)
            self.last_processed_ts.unwrap_or(self.pool.ts_init), // ts_init
        ))
    }

    /// Gets the count of positions that are currently active.
    ///
    /// Active positions are those with liquidity > 0 and whose tick range
    /// includes the current pool tick (meaning they have tokens in the pool).
    #[must_use]

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Process at least one pool event before calling `extract_snapshot`.
  2. Guard the call: check whether any events were processed and skip/make a fresh snapshot from genesis instead.
  3. If you need a baseline snapshot of an untouched pool, represent it as 'no snapshot / start from genesis' in your checkpoint scheme.
  4. In tests, drive the profiler with one synthetic event before extracting a snapshot.

Example fix

// before
let snapshot = profiler.extract_snapshot()?; // Err if nothing processed
// after
let snapshot = match profiler.extract_snapshot() {
    Ok(s) => Some(s),
    Err(e) if e.to_string().contains("no events processed yet") => None, // start from genesis
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: validation

Validate before calling

fn can_snapshot(profiler: &PoolProfiler) -> bool { profiler.last_processed_event.is_some() }

Try / catch

let snapshot = profiler.extract_snapshot()
    .map(Some)
    .or_else(|e| if e.to_string().contains("no events processed yet") { Ok(None) } else { Err(e) })?;

Prevention

When it happens

Trigger: Calling `extract_snapshot` on a freshly constructed `PoolProfiler` before any event has been applied via `process`/`process_defi_data` — i.e. `last_processed_event` is `None`.

Common situations: Checkpointing logic that runs too early in a replay pipeline; test code snapshotting a newly built profiler; resuming a job whose profiler was rebuilt but not yet fed any events.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/1932ce447546e405. Report an issue: GitHub.