{"record":{"id":"1be6585ca53b8a0f","repo":"nautechsystems/nautilus_trader","slug":"position-snapshot-blob-ref-blob-ref-skips-missin","errorCode":null,"errorMessage":"position snapshot blob_ref {blob_ref} skips missing frame {}","messagePattern":"position snapshot blob_ref (.+?) skips missing frame (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/cache/position.rs","lineNumber":284,"sourceCode":"    /// snapshot frames, conflicts with an existing frame, or does not decode to the expected\n    /// position snapshot.\n    pub fn restore_snapshot_blob(&mut self, blob_ref: &str, blob: Bytes) -> anyhow::Result<()> {\n        let (position_id, snapshot_index) = parse_position_snapshot_blob_ref(blob_ref)?;\n        let restored = decode_position_snapshot_blob(&position_id, blob.as_ref())?;\n\n        let frames = self.position_snapshots.entry(position_id).or_default();\n        match frames.get(snapshot_index) {\n            Some(existing) if existing.encoded()? == blob => {}\n            Some(_) => {\n                anyhow::bail!(\n                    \"position snapshot frame {snapshot_index} for {position_id} already exists with different bytes\"\n                );\n            }\n            None if frames.len() == snapshot_index => {\n                frames.push(PositionSnapshotFrame::new(restored, Some(blob.clone())));\n            }\n            None => {\n                anyhow::bail!(\n                    \"position snapshot blob_ref {blob_ref} skips missing frame {}\",\n                    frames.len()\n                );\n            }\n        }\n\n        self.general.insert(blob_ref.to_string(), blob);\n        Ok(())\n    }\n\n    fn snapshot_blob(&self, blob_ref: &str) -> Option<Bytes> {\n        if let Some(blob) = self.general.get(blob_ref) {\n            return Some(blob.clone());\n        }\n\n        self.position_snapshot_frame(blob_ref)?\n            .encoded()\n            .inspect_err(|e| log::warn!(\"Failed to encode position snapshot {blob_ref}: {e}\"))","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/cache/position.rs#L266-L302","documentation":"Snapshot frames must be restored contiguously: `restore_snapshot_blob` only appends a frame when `snapshot_index` equals the current length. A blob_ref whose index is greater than the number of stored frames would leave a gap, so the method bails reporting the first missing frame index.","triggerScenarios":"Restoring blobs out of order (index N before N-1), or restoring with a skipped/deleted frame (e.g. a missing file in the snapshot sequence, or filtering frames during restore).","commonSituations":"Manual recovery from a snapshot directory where one frame file is missing or corrupt and was skipped; parallel restores racing frames into the cache out of order.","solutions":["Restore snapshot blobs in ascending snapshot_index order.","Locate and restore the missing frame reported in the message (`frames.len()`) before continuing.","If the frame is unrecoverable, restore the position from a complete earlier snapshot lineage instead of a partial one."],"exampleFix":"// before\nfor blob in blobs.iter().rev() { cache.restore_snapshot_blob(...)?; } // out of order\n// after\nlet mut sorted = blobs.clone();\nsorted.sort_by_key(|(blob_ref, _)| blob_ref.snapshot_index);\nfor (blob_ref, blob) in sorted { cache.restore_snapshot_blob(blob_ref, blob)?; }","handlingStrategy":"validation","validationCode":"// ensure frames are contiguous and sorted by snapshot_index before restoring\nsorted_by_index.iter().enumerate().all(|(i, (blob_ref, _))| blob_ref.snapshot_index == i);","typeGuard":null,"tryCatchPattern":"match cache.restore_snapshot_blob(position_id, blob_ref, blob) {\n    Ok(()) => {},\n    Err(e) if e.to_string().contains(\"skips missing frame\") => {\n        // restore the missing frame reported in the message, in order\n    },\n    Err(e) => return Err(e),\n}","preventionTips":["Always restore snapshot blobs in ascending index order.","Verify the full snapshot file set exists before starting a restore.","Never skip corrupt frames mid-sequence; fall back to a complete snapshot."],"tags":["rust","positions","snapshot","restore","ordering"],"backgroundTag":"index-out-of-bounds","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}