nautechsystems/nautilus_trader · error

Profiler should have last_processed_event

Error message

Profiler should have last_processed_event

What it means

check_snapshot_validity unwraps profiler.last_processed_event with expect() when the snapshot was already validated during construction from RPC. The code assumes a profiler built from RPC state always records its last processed event; if that field is None despite already_validated being true, this line panics.

Source

Thrown at crates/adapters/blockchain/src/data/core.rs:1938

    /// # Errors
    ///
    /// Returns an error if database operations fail when persisting the validation state.
    ///
    /// # Panics
    ///
    /// Panics if the profiler does not have a last_processed_event when already_validated is true.
    pub async fn check_snapshot_validity(
        &self,
        profiler: &PoolProfiler,
        already_validated: bool,
    ) -> anyhow::Result<SnapshotValidation> {
        let (validation, block_position) = if already_validated {
            // Skip RPC call - profiler was validated during construction from RPC
            log::debug!("Snapshot already validated from RPC, skipping on-chain comparison");
            let last_event = profiler
                .last_processed_event
                .clone()
                .expect("Profiler should have last_processed_event");
            (SnapshotValidation::OnChain, Some(last_event))
        } else {
            // Fetch on-chain state and compare
            match self.get_on_chain_snapshot(profiler).await {
                Ok(on_chain_snapshot) => {
                    log::debug!("Comparing profiler state with on-chain state...");
                    let comparison = compare_pool_profiler_detailed(profiler, &on_chain_snapshot);
                    let validation = if comparison.is_valid_for_snapshot() {
                        if !comparison.is_exact_match() {
                            log::warn!(
                                "Pool profiler snapshot has a non-structural mismatch (sqrt ratio, fee protocol, or protocol fees); accepting snapshot"
                            );
                        }
                        SnapshotValidation::OnChain
                    } else {
                        log::error!(
                            "Pool profiler state does NOT match on-chain smart contract state"
                        );

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the PoolProfiler is constructed via the RPC path that populates last_processed_event before marking it validated.
  2. If loading persisted snapshots, migrate/repair snapshots so last_processed_event is present, or force re-validation by setting already_validated=false.
  3. In the library, replace expect with ok_or + error propagation so invalid profilers yield a recoverable error instead of a panic.

Example fix

// before
let last_event = profiler.last_processed_event.clone().expect("Profiler should have last_processed_event");
// after
let last_event = profiler.last_processed_event.clone().ok_or_else(|| {
    anyhow::anyhow!("profiler marked as validated but has no last_processed_event")
})?;
Defensive patterns

Strategy: validation

Validate before calling

if profiler.already_validated && profiler.last_processed_event.is_none() {
    anyhow::bail!("profiler claims validation but lacks last_processed_event; rebuild from RPC");
}
let (validation, block_position) = engine.check_snapshot_validity(&mut profiler).await?;

Type guard

fn validated_profiler_has_event(p: &PoolProfiler) -> bool {
    !p.already_validated || p.last_processed_event.is_some()
}

Try / catch

// Panics are not catchable as errors; validate inputs beforehand.
match std::panic::catch_unwind(|| engine.check_snapshot_validity(&mut profiler)) {
    Ok(inner) => inner?,
    Err(_) => anyhow::bail!("panic validating snapshot: profiler missing last_processed_event"),
}

Prevention

When it happens

Trigger: Calling check_snapshot_validity with a PoolProfiler whose already_validated flag is true but whose last_processed_event is None — e.g. a profiler constructed or deserialized from a snapshot that skipped event tracking, passed to check_snapshot_validity from tests or RPC-triggered validation paths.

Common situations: Restoring a profiler from a persisted snapshot that lost the last_processed_event field (older schema version); constructing a PoolProfiler manually in tests with already_validated=true; a bug in the construction path that sets validity without setting the event.

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


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