nautechsystems/nautilus_trader · error

position snapshot id {} does not match blob_ref position {po

Error message

position snapshot id {} does not match blob_ref position {position_id}

What it means

decode_position_snapshot_blob deserializes a JSON Position snapshot and verifies its 'id' has the form '<position_id>-<uuid4>'. This error means the snapshot's id does not start with the position id from the blob_ref, so the blob belongs to a different position than the ref claims.

Source

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

        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!(
            "position snapshot id {} does not match blob_ref position {position_id}",
            snapshot.id
        );
    };

    if UUID4::from_str(snapshot_uuid).is_err() {
        anyhow::bail!(
            "position snapshot id {} does not match blob_ref position {position_id}",
            snapshot.id
        );
    }

    Ok(snapshot)
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the blob_ref and blob are a matched pair from the same write (same position)
  2. Re-export the snapshot so the ref and blob are regenerated together
  3. Check that external storage didn't reorder or re-key blobs relative to their refs
Defensive patterns

Strategy: validation

Validate before calling

let snapshot: Position = serde_json::from_slice(&blob)?;
if !snapshot.id.as_str().starts_with(&format!("{position_id}-")) {
    return Err(anyhow!("blob does not belong to position {position_id}"));
}

Type guard

fn blob_matches_position(snapshot_id: &str, position_id: &PositionId) -> bool {
    snapshot_id.starts_with(&format!("{}-", position_id.as_str()))
}

Try / catch

match cache.restore_snapshot_blob(&blob_ref, &blob) {
    Err(e) if e.to_string().contains("does not match blob_ref position") => {
        // ref/blob pair is inconsistent: re-fetch or re-export the snapshot
    }
    other => other?,
}

Prevention

When it happens

Trigger: restore_snapshot_blob called with a (blob_ref, blob) pair that was mismatched — e.g. the blob stored under one position's ref actually contains another position's snapshot, or the position_id parsed from the ref was altered.

Common situations: Ref and blob stored/transported out of sync in external storage; hand-editing blob_refs; a cache backend that re-keyed blobs; version changes to the '<id>-<uuid>' snapshot id format.

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/31f52e2356d6309d. Report an issue: GitHub.