nautechsystems/nautilus_trader · error · anyhow::Error
unknown position_side
Error message
unknown position_side
What it means
make_venue_position_id builds a venue PositionId from the position_side field of exchange order updates. BinancePositionSide::Unknown has no mapping, so the function bails with 'unknown position_side'. Both and Long/Short have defined behavior (None and LONG/SHORT suffix).
Source
Thrown at crates/adapters/binance/src/futures/websocket/streams/dispatch.rs:1136
///
/// # Errors
///
/// Returns an error when position IDs are enabled but the position side is missing or unknown.
pub(crate) fn make_venue_position_id(
use_position_ids: bool,
instrument_id: InstrumentId,
position_side: Option<BinancePositionSide>,
) -> anyhow::Result<Option<PositionId>> {
if !use_position_ids {
return Ok(None);
}
let position_side = position_side.context("missing position_side")?;
let side = match position_side {
BinancePositionSide::Long => "LONG",
BinancePositionSide::Short => "SHORT",
BinancePositionSide::Both => return Ok(None),
BinancePositionSide::Unknown => anyhow::bail!("unknown position_side"),
};
Ok(Some(PositionId::new(format!("{instrument_id}-{side}"))))
}
/// Dispatches exchange-generated order fills (liquidation, ADL, settlement).
///
/// Bundles the parsed `OrderStatusReport` and `FillReport` into a single
/// `OrderWithFills` send so the engine creates the external order from the
/// status report and applies the real fill (preserving `trade_id` and
/// `commission`) instead of synthesizing one. Falls back to whichever report
/// parsed if the other parser fails.
///
/// Skips events with zero fill quantity (pending liquidation notifications).
#[expect(clippy::too_many_arguments)]
pub(crate) fn dispatch_exchange_generated_fill(
msg: &BinanceFuturesOrderUpdateMsg,
emitter: &ExecutionEventEmitter,
instrument_id: InstrumentId,View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the raw payload's positionSide value and confirm it is one of LONG, SHORT, BOTH.
- Update the BinancePositionSide enum/deserializer if Binance added a new variant.
- Fix mock/test payloads to emit valid positionSide values.
Example fix
// before
{"positionSide": "BOTH "} // unrecognized due to whitespace -> Unknown
// after
{"positionSide": "BOTH"} // valid: returns Ok(None) in one-way mode Defensive patterns
Strategy: validation
Validate before calling
fn known_position_side(raw: &str) -> bool {
matches!(raw, "LONG" | "SHORT" | "BOTH")
} Try / catch
match result {
Err(e) if e.to_string().contains("unknown position_side") => {
tracing::error!("unrecognized positionSide in update: log raw payload and inspect");
}
r => r?,
} Prevention
- Log raw payloads when the adapter version predates a Binance enum change.
- Keep the BinancePositionSide enum in sync with exchange API docs.
- Sanitize mock/test payloads to emit only LONG/SHORT/BOTH.
When it happens
Trigger: dispatch_order_update or dispatch_algo_update receives an order update whose positionSide deserializes to BinancePositionSide::Unknown (typically an unrecognized side string from the exchange) while position IDs are enabled.
Common situations: A new/renamed Binance positionSide value the adapter does not recognize; corrupted or non-standard payloads (e.g. from a test mock or API change); deserializer defaulting unknown enum variants to Unknown.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- BinanceFuturesWebSocketClient requires UsdM or CoinM product
- missing positive trigger_price for Binance algo order type {
- missing positive price for Binance algo order type {:?}
- old user stream dispatch task failed: {error}
- old user stream dispatch task did not stop after abort
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/60073d3c29a1fdca.
Report an issue: GitHub.