nautechsystems/nautilus_trader · error
replacement venue-leg side {:?} does not match logical order
Error message
replacement venue-leg side {:?} does not match logical order side {} What it means
During replacement-leg promotion, the venue report's order side must match the logical order side recorded in the old leg's context identity. Polymarket legs can be expressed via token buys, so the adapter maps logical BUY/SELL to venue-leg sides; this ensure! fires when the venue's reported side disagrees with that mapping.
Source
Thrown at crates/adapters/polymarket/src/execution/reports.rs:727
};
let context = self
.order_contexts
.get(&promotion.old_venue_order_id)
.context("pending modification has no old-leg context")?;
anyhow::ensure!(
report.quantity == promotion.leg_quantity,
"replacement venue-leg quantity {} does not match signed quantity {}",
report.quantity,
promotion.leg_quantity,
);
anyhow::ensure!(
report.price == Some(promotion.price),
"replacement venue-leg price {:?} does not match signed price {}",
report.price,
promotion.price,
);
anyhow::ensure!(
report.order_side == Some(context.identity.order_side),
"replacement venue-leg side {:?} does not match logical order side {}",
report.order_side,
context.identity.order_side,
);
let cached_order = self
.core
.cache()
.order_owned(&promotion.client_order_id)
.context("pending modification has no cached logical order")?;
if report.order_status == OrderStatus::Rejected {
let finish = self
.ws_dispatch_state
.lock()
.finish_modify_without_replacement(
promotion.client_order_id,
promotion.old_venue_order_id,View on GitHub (pinned to 18893faf8b)
Solutions
- Fix the logical-to-venue-leg side mapping in the replacement construction
- Verify the context identity side matches the original submitted order
- Inspect the venue response to confirm which leg the report refers to
- Re-register the context with the correct side and retry
Example fix
// before
let leg_side = if order.side() == OrderSide::Buy { Buy } else { Buy }; // wrong: always Buy
// after
let leg_side = venue_leg_side_for(order.side(), token_id); // correct logical mapping Defensive patterns
Strategy: validation
Validate before calling
let expected_side = venue_leg_side_for(order.side(), leg_token_id); anyhow::ensure!(context.identity.order_side == order.side(), "context side must match logical order side");
Type guard
fn side_matches(report: &OrderStatusReport, ctx: &OrderContext) -> bool {
report.order_side == Some(ctx.identity.order_side)
} Try / catch
match report.order_side {
Some(s) if s != context.identity.order_side => error!("side inversion in replace leg — abort promotion"),
None => warn!("venue omitted side; falling back to context side"),
_ => {},
} Prevention
- Centralize the logical-side to venue-leg-side mapping in one tested function
- Add unit tests covering BUY and SELL replacements on both outcome tokens
- Never hardcode side conversions inline in report-generation code
When it happens
Trigger: generate_order_status_reports promotes a pending modification and report.order_side is None or differs from context.identity.order_side — e.g. side inversion in the replace/leg construction.
Common situations: Incorrect BUY/SELL mapping when constructing the replacement leg (e.g. SELL implemented as BUY of the complement token); venue returning side for the wrong leg; context built with the wrong logical side at registration.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- replacement venue-leg quantity {} does not match signed quan
- replacement venue-leg price {:?} does not match signed price
- Invalid order side: {e}
- Binance liquidation custom data requires BINANCE venue instr
- Binance Futures custom data requires BINANCE venue instrumen
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f4d0c704326270b9.
Report an issue: GitHub.