nautechsystems/nautilus_trader · error
position snapshot blob_ref {blob_ref} has empty position id
Error message
position snapshot blob_ref {blob_ref} has empty position id What it means
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.
Source
Thrown at crates/common/src/cache/position.rs:454
.get(position_id)
.is_some_and(|position| position.borrow().instrument_id == *instrument_id)
})
.copied()
.collect()
}
}
fn parse_position_snapshot_blob_ref(blob_ref: &str) -> anyhow::Result<(PositionId, usize)> {
let Some(rest) = blob_ref.strip_prefix("cache://position-snapshots/") else {
anyhow::bail!("unsupported cache snapshot blob_ref {blob_ref}");
};
let Some((position_id, snapshot_index)) = rest.rsplit_once('/') else {
anyhow::bail!("malformed position snapshot blob_ref {blob_ref}");
};
if position_id.is_empty() {
anyhow::bail!("position snapshot blob_ref {blob_ref} has empty position id");
}
let snapshot_index = snapshot_index.parse::<usize>().map_err(|e| {
anyhow::anyhow!("position snapshot blob_ref {blob_ref} has invalid frame index: {e}")
})?;
Ok((PositionId::new(position_id), snapshot_index))
}
fn decode_position_snapshot_blob(
position_id: &PositionId,
blob: &[u8],
) -> anyhow::Result<Position> {
let snapshot = serde_json::from_slice::<Position>(blob)?;
let expected_prefix = format!("{}-", position_id.as_str());
let Some(snapshot_uuid) = snapshot.id.as_str().strip_prefix(&expected_prefix) else {
anyhow::bail!(View on GitHub (pinned to 18893faf8b)
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
Example fix
// before
let blob_ref = format!("cache://position-snapshots/{}/{}", "", index);
// after
assert!(!position_id.as_str().is_empty());
let blob_ref = format!("cache://position-snapshots/{}/{}", position_id, index); Defensive patterns
Strategy: validation
Validate before calling
let rest = blob_ref.strip_prefix("cache://position-snapshots/").expect("prefix");
let (pid, _) = rest.rsplit_once('/').expect("separator");
assert!(!pid.is_empty(), "blob_ref has empty position id"); Type guard
fn has_non_empty_position_id(blob_ref: &str) -> bool {
blob_ref.strip_prefix("cache://position-snapshots/")
.and_then(|rest| rest.rsplit_once('/'))
.map(|(pid, _)| !pid.is_empty())
.unwrap_or(false)
} Try / catch
match cache.position_snapshot_frame(&blob_ref) {
Err(e) if e.to_string().contains("empty position id") => log::error!("blob_ref built from empty PositionId; check upstream data"),
other => other?,
} Prevention
- Validate PositionId is non-empty at the point of ref construction
- Avoid interpolating Option/empty values into blob_ref format strings
When it happens
Trigger: Passing a blob_ref like 'cache://position-snapshots//3' where the position id segment is empty.
Common situations: An empty/None position_id interpolated into a format string during ref construction; data corruption dropping the id when serializing the ref.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- unsupported cache snapshot blob_ref {blob_ref}
- malformed position snapshot blob_ref {blob_ref}
- DataActor {} must be registered before calling `cache()` - t
- Order {client_order_id} not found
- Position {position_id} not found
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/8b809be0e9fcb21b.
Report an issue: GitHub.