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
- Clear the existing position_snapshots state before restoring a different snapshot set.
- Verify the blob source: restore only one consistent snapshot lineage per position.
- 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
- Restore from a single snapshot lineage per position.
- Clear prior snapshot state before re-running a restore.
- Verify snapshot file integrity (hashes) before loading.
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
- position snapshot blob_ref {blob_ref} skips missing frame {}
- List of Positions is empty
- Unknown position currency '{pos_ccy}' for instrument {instru
- position snapshot id {} does not match blob_ref position {po
- Execution algorithm {restore_actor_id} not found while resto
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c91e35f328667ae9.
Report an issue: GitHub.