nautechsystems/nautilus_trader · error

position snapshot frame {snapshot_index} for {position_id} a

Error message

position snapshot frame {snapshot_index} for {position_id} already exists with different bytes

What it means

`restore_snapshot_blob` restores a position snapshot frame at `snapshot_index`. If a frame already exists at that index, it is only accepted when the encoded bytes are identical; different bytes at the same index indicate a conflicting snapshot blob for that position, so the restore bails and leaves state untouched.

Source

Thrown at crates/common/src/cache/position.rs:276

    /// Restores the cache-owned snapshot blob stored under `blob_ref`.
    ///
    /// Only cache-owned `cache://position-snapshots/...` blobs are currently supported.
    ///
    /// # Errors
    ///
    /// Returns an error if the blob reference is unsupported, malformed, skips earlier
    /// snapshot frames, conflicts with an existing frame, or does not decode to the expected
    /// position snapshot.
    pub fn restore_snapshot_blob(&mut self, blob_ref: &str, blob: Bytes) -> anyhow::Result<()> {
        let (position_id, snapshot_index) = parse_position_snapshot_blob_ref(blob_ref)?;
        let restored = decode_position_snapshot_blob(&position_id, blob.as_ref())?;

        let frames = self.position_snapshots.entry(position_id).or_default();
        match frames.get(snapshot_index) {
            Some(existing) if existing.encoded()? == blob => {}
            Some(_) => {
                anyhow::bail!(
                    "position snapshot frame {snapshot_index} for {position_id} already exists with different bytes"
                );
            }
            None if frames.len() == snapshot_index => {
                frames.push(PositionSnapshotFrame::new(restored, Some(blob.clone())));
            }
            None => {
                anyhow::bail!(
                    "position snapshot blob_ref {blob_ref} skips missing frame {}",
                    frames.len()
                );
            }
        }

        self.general.insert(blob_ref.to_string(), blob);
        Ok(())
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Clear the existing position_snapshots state before restoring a different snapshot set.
  2. Verify the blob source: restore only one consistent snapshot lineage per position.
  3. If bytes differ only due to encoding-version drift, re-serialize from the original source with the current version rather than re-restoring old blobs.
Defensive patterns

Strategy: try-catch

Validate before calling

// before restoring, confirm no frame exists at this index or that bytes match:
// compare the incoming blob against any existing snapshot source before calling restore_snapshot_blob

Try / catch

match cache.restore_snapshot_blob(position_id, blob_ref, blob) {
    Ok(()) => {},
    Err(e) if e.to_string().contains("already exists with different bytes") => {
        // reset snapshot state or switch to a single consistent snapshot lineage
    },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `restore_snapshot_blob` twice for the same (position_id, snapshot_index) with different blobs — e.g. restoring snapshots from two sources/replays, a corrupted or truncated blob, or mixing snapshot files from different sessions.

Common situations: Recovering a trader from multiple backup files where one snapshot was taken at a different point; re-running a restore without clearing previous snapshot state; a build/version change altering snapshot encoding.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — 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/c91e35f328667ae9. Report an issue: GitHub.