nautechsystems/nautilus_trader · error · anyhow::Error
incompatible cached {position_side:?} position IDs for {inst
Error message
incompatible cached {position_side:?} position IDs for {instrument_id}: {}; expected {venue_position_id} What it means
When use_position_ids=true, the adapter canonically names each position ID after the venue position (instrument + hedge side). ensure_cached_position_id_compatible scans the Nautilus cache for open positions of the same instrument/side/account whose IDs differ from the canonical venue ID; any such legacy or synthetic IDs would break identity tracking, so the error lists them and aborts.
Source
Thrown at crates/adapters/binance/src/futures/execution.rs:1087
position_side: PositionSide,
venue_position_id: PositionId,
) -> anyhow::Result<()> {
let cache = self.core.cache();
let mut incompatible_ids: Vec<_> = cache
.positions_open(
Some(&BINANCE_VENUE),
Some(&instrument_id),
None,
Some(&self.core.account_id),
Some(position_side),
)
.into_iter()
.filter(|position| position.id != venue_position_id)
.map(|position| position.id.to_string())
.collect();
incompatible_ids.sort_unstable();
anyhow::ensure!(
incompatible_ids.is_empty(),
"incompatible cached {position_side:?} position IDs for {instrument_id}: {}; expected {venue_position_id}",
incompatible_ids.join(", "),
);
Ok(())
}
async fn generate_open_order_status_reports(
&self,
instrument_id: Option<InstrumentId>,
ts_init: UnixNanos,
) -> anyhow::Result<Vec<OpenOrderStatusReport>> {
if let Some(instrument_id) = instrument_id
&& self
.http_client
.instrument_reconciliation(&instrument_id)
.is_none()
{View on GitHub (pinned to 18893faf8b)
Solutions
- Clear stale cached open positions for the affected instrument (purge/rebuild the cache database) so only venue position IDs remain.
- Run one clean reconciliation with use_position_ids=true from an empty cache.
- Keep use_position_ids setting stable across restarts; do not toggle between virtual and venue position IDs on the same cache.
- Close the conflicting positions and let the adapter recreate them with canonical venue IDs.
Defensive patterns
Strategy: validation
Validate before calling
let stale: Vec<_> = cache.positions_open(Some(&BINANCE_VENUE), Some(&instrument_id), None, Some(&account_id), Some(side))
.into_iter().filter(|p| p.id != expected_venue_id).collect();
if !stale.is_empty() { /* purge or re-create cached positions before reconciliation */ } Prevention
- Keep use_position_ids stable across restarts
- Start live trading against a clean cache when toggling position-ID modes
- Do not mix backtest/replay caches with live venue position IDs
When it happens
Trigger: Reconciliation (create_position_report / generate_position_status_reports) finds open cached positions for an instrument+side that were created before use_position_ids was enabled, or by a different run with virtual (non-venue) position IDs.
Common situations: Restarting a trader after flipping use_position_ids=true on a cache populated with virtual position IDs; mixing strategy-generated PositionIds with venue IDs for the same instrument; replay/backtest cache reused in live trading.
Related errors
- instrument metadata ID {} does not match {instrument_id}
- actual order ID mismatch: expected {expected_actual_order_id
- actual order symbol mismatch: expected {}, was {}
- actual order side mismatch: expected {:?}, was {:?}
- unknown position_side
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/72bebb294d0a85b5.
Report an issue: GitHub.