nautechsystems/nautilus_trader · error
{evidence} side {actual} does not match known order side {ex
Error message
{evidence} side {actual} does not match known order side {expected} What it means
validate_expected_order_side cross-checks the side implied by trade/order evidence against the side already recorded for the known order. If a target trade's side (from classify_target_trade) contradicts the known order's side, the reconciliation cannot be trusted and this error is raised with the evidence label. It prevents mis-attributing fills to the wrong order side.
Source
Thrown at crates/adapters/polymarket/src/execution/reconciliation.rs:143
mut self,
expected_order_side: Option<OrderSide>,
) -> Self {
self.expected_order_side = if self.venue_order_id.is_some() {
expected_order_side
} else {
None
};
self
}
}
fn validate_expected_order_side(
expected: Option<OrderSide>,
actual: OrderSide,
evidence: &str,
) -> anyhow::Result<()> {
if let Some(expected) = expected {
anyhow::ensure!(
actual == expected,
"{evidence} side {actual} does not match known order side {expected}",
);
}
Ok(())
}
fn validate_target_trade_role(
trade: &PolymarketTradeReport,
venue_order_id: VenueOrderId,
) -> anyhow::Result<bool> {
let target_is_taker = trade.taker_order_id == venue_order_id.as_str();
let target_maker_occurrences = trade
.maker_orders
.iter()
.filter(|order| order.order_id == venue_order_id.as_str())
.count();
let target_is_maker = target_maker_occurrences > 0;View on GitHub (pinned to 18893faf8b)
Solutions
- Log the evidence string and both sides to identify which order the trade was matched against.
- Fix the trade-to-order matching logic in classify_target_trade (match on order ID/volume first).
- Refresh cached order state from the venue to rule out a stale recorded side.
Example fix
// before
let trade = pick_any_trade(fills); // may match wrong order
validate_expected_order_side(order.side(), trade.side, "target-trade")?;
// after
let trade = fills.iter().find(|t| t.order_id == order.venue_order_id())
.context("no fill for this order")?;
validate_expected_order_side(order.side(), trade.side, "target-trade")?; Defensive patterns
Strategy: validation
Validate before calling
if let Some(expected) = order.side() {
if trade.side != expected { return Err(anyhow!("side mismatch for order {:?}", order.venue_order_id())); }
} Try / catch
match classify_target_trade(trades, &order) {
Ok(t) => t,
Err(e) if e.to_string().contains("does not match known order side") => { log::warn!("side mismatch: {e}; refreshing order state"); refresh_order_from_venue(order.venue_order_id())? }
Err(e) => return Err(e),
} Prevention
- Match trades to orders by venue order ID, not by heuristic
- Refresh cached order state before reconciliation
- Be explicit about venue side-reporting conventions (maker vs taker)
When it happens
Trigger: classify_target_trade encounters a fill/trade whose BUY/SELL side differs from the side stored on the matched order — e.g. matching a trade to the wrong order, a venue reporting taker side vs maker side inconsistently, or stale order state after a manual position change.
Common situations: Venue webhooks reporting the counterparty side; two open orders on opposite sides with overlapping fills being mixed up; cache holding an outdated order after a modify.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Finalized Swap side {} does not match {} order
- order side differs across fill group
- Unsupported `OrderSide` for Binance: {value:?}
- invalid OrderSide: must be Buy or Sell, was {side}
- Invalid order side: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/27ebc9fc392ae75a.
Report an issue: GitHub.