nautechsystems/nautilus_trader · error
position {position_id} is not cached
Error message
position {position_id} is not cached What it means
During fill-void processing the engine takes exclusive ownership of the position (position_owned) from the cache to mutate its fill-void records. If the position identified by position_id is not present in the cache, the engine cannot apply the void and returns this error. The library expects every position referenced by a void event to have been created and cached by prior fill events.
Source
Thrown at crates/execution/src/engine/mod.rs:3984
"position fragments do not cover voided commission for fill {}",
event.trade_id
);
}
let mut corrected_positions = Vec::new();
for (position_id, (voided_qty, commission_voided)) in allocations {
if voided_qty.is_zero() {
anyhow::bail!(
"commission-only position correction requires authoritative reconciliation for fill {}",
event.trade_id
);
}
let mut position = self
.cache
.borrow()
.position_owned(&position_id)
.ok_or_else(|| anyhow::anyhow!("position {position_id} is not cached"))?;
let previous = position
.fill_voids
.iter()
.rev()
.find(|record| {
record.event.client_order_id == event.client_order_id
&& record.event.trade_id == event.trade_id
})
.map(|record| (record.voided_qty, record.commission_voided));
if previous == Some((voided_qty, commission_voided)) {
continue;
}
let corrected_qty = previous.map_or(voided_qty, |(prior_qty, _)| {
voided_qty.saturating_sub(prior_qty)
});
// `events` holds the fills since the position was last flat, because `apply_fill`
// clears it when reopening from flat. A NETTING flip splits one fill across theView on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the cache is loaded from the same snapshot/session that contains the position before applying void events.
- Replay fills and voids together in order so the position exists in cache when the void is processed.
- Skip or drop void events whose position_id is unknown only if your recovery policy explicitly tolerates them — otherwise rehydrate state.
- Log position_id and inspect cache contents (cache.position(&position_id)) before dispatching the void to confirm presence.
Example fix
// before: applying a void with an empty cache
let event = FillVoided { position_id: Some(pid), .. };
engine.apply_fill_void(event)?; // 'position ... is not cached'
// after: rehydrate cache first
assert!(cache.position(&pid).is_some(), "rehydrate cache snapshot before voids");
engine.apply_fill_void(event)?; Defensive patterns
Strategy: validation
Validate before calling
// confirm the position exists and is retrievable before applying any void
if cache.position(&position_id).is_none() {
return Err(anyhow::anyhow!(
"refusing to void fill {}: position {position_id} missing; rehydrate cache first",
event.trade_id
));
} Type guard
fn position_cached(cache: &Cache, position_id: &PositionId) -> bool {
cache.position(position_id).is_some()
} Try / catch
match engine.apply_fill_void(event) {
Err(e) if e.to_string().contains("is not cached") => {
log::warn!("skipping void for uncached position: {e}");
// rehydrate cache from snapshot, then retry
}
other => other?,
} Prevention
- Always replay fills before voids so positions exist in cache.
- Load the cache snapshot that matches the event stream segment being replayed.
- Avoid multiple writers deleting positions from a shared cache.
When it happens
Trigger: A fill-void event references a position_id that was never cached (fills applied before cache persistence, cache flushed/reset mid-session), or the position was previously removed/archived before the void arrived.
Common situations: Running with a fresh cache while replaying historical events; cache snapshot written before the position was opened; multiple processes sharing a cache where one deleted the position; adapter (e.g. Betfair) emitting voids for positions from a prior session.
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
- Position {position_id} not found
- Order for {} not found to determine position ID
- position fragments do not cover voided quantity for fill {}
- position fragments do not cover voided commission for fill {
- DataActor {} must be registered before calling `cache()` - t
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/4f95b9f750a23345.
Report an issue: GitHub.