{"record":{"id":"8b809be0e9fcb21b","repo":"nautechsystems/nautilus_trader","slug":"position-snapshot-blob-ref-blob-ref-has-empty-po","errorCode":null,"errorMessage":"position snapshot blob_ref {blob_ref} has empty position id","messagePattern":"position snapshot blob_ref (.+?) has empty position id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/cache/position.rs","lineNumber":454,"sourceCode":"                    .get(position_id)\n                    .is_some_and(|position| position.borrow().instrument_id == *instrument_id)\n            })\n            .copied()\n            .collect()\n    }\n}\n\nfn parse_position_snapshot_blob_ref(blob_ref: &str) -> anyhow::Result<(PositionId, usize)> {\n    let Some(rest) = blob_ref.strip_prefix(\"cache://position-snapshots/\") else {\n        anyhow::bail!(\"unsupported cache snapshot blob_ref {blob_ref}\");\n    };\n\n    let Some((position_id, snapshot_index)) = rest.rsplit_once('/') else {\n        anyhow::bail!(\"malformed position snapshot blob_ref {blob_ref}\");\n    };\n\n    if position_id.is_empty() {\n        anyhow::bail!(\"position snapshot blob_ref {blob_ref} has empty position id\");\n    }\n\n    let snapshot_index = snapshot_index.parse::<usize>().map_err(|e| {\n        anyhow::anyhow!(\"position snapshot blob_ref {blob_ref} has invalid frame index: {e}\")\n    })?;\n\n    Ok((PositionId::new(position_id), snapshot_index))\n}\n\nfn decode_position_snapshot_blob(\n    position_id: &PositionId,\n    blob: &[u8],\n) -> anyhow::Result<Position> {\n    let snapshot = serde_json::from_slice::<Position>(blob)?;\n    let expected_prefix = format!(\"{}-\", position_id.as_str());\n\n    let Some(snapshot_uuid) = snapshot.id.as_str().strip_prefix(&expected_prefix) else {\n        anyhow::bail!(","sourceCodeStart":436,"sourceCodeEnd":472,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/cache/position.rs#L436-L472","documentation":"parse_position_snapshot_blob_ref rejects a position-snapshot reference whose path segment after the prefix contains an empty position id, i.e. the blob_ref is malformed and cannot identify a snapshot.","triggerScenarios":"Passing a blob_ref like 'cache://position-snapshots//3' where the position id segment is empty.","commonSituations":"An empty/None position_id interpolated into a format string during ref construction; data corruption dropping the id when serializing the ref.","solutions":["Populate the actual PositionId string in the blob_ref before calling","Check that the source position_id is non-empty (and valid) when building the ref","Reject empty ids upstream so malformed refs never reach the cache API"],"exampleFix":"// before\nlet blob_ref = format!(\"cache://position-snapshots/{}/{}\", \"\", index);\n// after\nassert!(!position_id.as_str().is_empty());\nlet blob_ref = format!(\"cache://position-snapshots/{}/{}\", position_id, index);","handlingStrategy":"validation","validationCode":"let rest = blob_ref.strip_prefix(\"cache://position-snapshots/\").expect(\"prefix\");\nlet (pid, _) = rest.rsplit_once('/').expect(\"separator\");\nassert!(!pid.is_empty(), \"blob_ref has empty position id\");","typeGuard":"fn has_non_empty_position_id(blob_ref: &str) -> bool {\n    blob_ref.strip_prefix(\"cache://position-snapshots/\")\n        .and_then(|rest| rest.rsplit_once('/'))\n        .map(|(pid, _)| !pid.is_empty())\n        .unwrap_or(false)\n}","tryCatchPattern":"match cache.position_snapshot_frame(&blob_ref) {\n    Err(e) if e.to_string().contains(\"empty position id\") => log::error!(\"blob_ref built from empty PositionId; check upstream data\"),\n    other => other?,\n}","preventionTips":["Validate PositionId is non-empty at the point of ref construction","Avoid interpolating Option/empty values into blob_ref format strings"],"tags":["cache","blob-ref","empty-required-field","rust"],"backgroundTag":"empty-required-field","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"}