nautechsystems/nautilus_trader · error

Cannot update position {position_id}: not found in cache

Error message

Cannot update position {position_id}: not found in cache

What it means

`update_position_from_fill` looks up the position by PositionId and applies an OrderFilled event to it in place. If the position is not in the cache, the fill cannot be applied, so the method bails — it never fabricates a position from a fill alone.

Source

Thrown at crates/common/src/cache/mod.rs:5466

        Ok(())
    }

    /// Updates a cached position by applying an order fill in place.
    ///
    /// Returns a transient copy of the updated state without stored history. The canonical cached
    /// position retains its complete history.
    ///
    /// # Errors
    ///
    /// Returns an error if the position is not already held in the cache, or if updating the
    /// position in the database fails.
    pub fn update_position_from_fill(
        &mut self,
        position_id: PositionId,
        fill: &OrderFilled,
    ) -> anyhow::Result<Position> {
        let Some(position_cell) = self.positions.get(&position_id).cloned() else {
            anyhow::bail!("Cannot update position {position_id}: not found in cache");
        };

        let position = {
            let mut position = position_cell.borrow_mut();
            position.apply(fill);
            position.clone_without_events()
        };

        self.refresh_position_indexes(&position);

        if let Some(database) = &mut self.database {
            database.update_position(&position_cell.borrow())?;
        }

        Ok(position)
    }

    fn refresh_position_indexes(&mut self, position: &Position) {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the opening event that creates the position is processed before its fills.
  2. Check `cache.position(&position_id)` and, if absent, rebuild the position from the fill per your OMS policy instead of calling this API.
  3. Disable/adjust aggressive position purging, or restore positions from snapshots before applying fills.

Example fix

// before
let position = cache.update_position_from_fill(position_id, &fill)?;
// after
if cache.position(&position_id).is_none() {
    // rebuild or open the position from the fill per OMS policy
}
let position = cache.update_position_from_fill(position_id, &fill)?;
Defensive patterns

Strategy: validation

Validate before calling

if cache.position(&position_id).is_none() {
    // position missing: rebuild/open it per OMS policy before applying the fill
}

Try / catch

match cache.update_position_from_fill(position_id, &fill) {
    Ok(p) => {},
    Err(e) if e.to_string().contains("not found in cache") => { /* recover: rebuild position or open new */ },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Applying a fill whose `position_id` references a position not cached (e.g. the position was never opened through the cache, was purged, or the fill's position_id is stale/mismatched after a snapshot restore).

Common situations: Backtesting/live runs where position events arrive after cache purging; desynchronized OMS state where fills reference positions from a previous session; incomplete snapshot restore missing the position record.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/aa5bdecc64f30a5f. Report an issue: GitHub.