nautechsystems/nautilus_trader · error · anyhow::Error

position_side LONG conflicts with negative position_amt

Error message

position_side LONG conflicts with negative position_amt

What it means

During position-report reconciliation, the adapter derives a local PositionSide purely from the sign of Binance's position_amt (positive=Long, negative=Short). When use_position_ids=true and Binance's explicit positionSide field says LONG, the adapter requires the derived side to match; a mismatch means the position_amt sign contradicts the venue's declared hedge side, so the report would be internally inconsistent and is rejected.

Source

Thrown at crates/adapters/binance/src/futures/execution.rs:1025

        if position_amount.is_zero() {
            anyhow::bail!("Position is flat");
        }

        let entry_price: Decimal = position
            .entry_price
            .parse()
            .context("invalid entry_price")?;

        let position_side = if position_amount > Decimal::ZERO {
            PositionSide::Long
        } else {
            PositionSide::Short
        };

        if self.config.use_position_ids {
            match position.position_side {
                Some(BinancePositionSide::Long) => anyhow::ensure!(
                    position_side == PositionSide::Long,
                    "position_side LONG conflicts with negative position_amt"
                ),
                Some(BinancePositionSide::Short) => anyhow::ensure!(
                    position_side == PositionSide::Short,
                    "position_side SHORT conflicts with positive position_amt"
                ),
                _ => {}
            }
        }

        let venue_position_id = make_venue_position_id(
            self.config.use_position_ids,
            instrument_id,
            position.position_side,
        )?;

        if let Some(venue_position_id) = venue_position_id {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the account's position mode (one-way vs hedge) in Binance Futures settings and ensure it matches the adapter's configuration; reconcile after switching.
  2. Set use_position_ids=false in the Binance Futures execution config to skip venue-position-ID validation (virtual hedging).
  3. Re-pull fresh position risk data; a transient mid-close snapshot can produce sign/side disagreement.
  4. If persisting, clear stale cached Nautilus positions for the instrument so reconciliation starts clean.

Example fix

// config: skip venue position-ID identity checks
// before
BinanceFuturesExecClientConfig { use_position_ids: true, .. }
// after
BinanceFuturesExecClientConfig { use_position_ids: false, .. }
Defensive patterns

Strategy: validation

Validate before calling

if cfg.use_position_ids {
    let amt: Decimal = position.position_amt.parse()?;
    if position.position_side == Some(BinancePositionSide::Long) && amt < Decimal::ZERO {
        log::warn!("inconsistent LONG side with negative amt for {}", position.symbol);
    }
}

Prevention

When it happens

Trigger: generate_order_status_reports -> generate_position_status_reports -> create_position_report with a BinancePositionRisk where position_side=Some(Long) but position_amt parses to a negative Decimal (or vice versa for 1841). Typically caused by stale/restored one-way-mode data or hedge-mode positions flipped without a corresponding amt sign change.

Common situations: Switching an account between one-way and hedge mode while old position snapshots are cached; running with use_position_ids=true (venue position identity mode) on an account whose positionSide metadata is inconsistent with the AMT sign after manual liquidation in the Binance UI; race during reconciliation where a position just crossed zero.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/8c5e9ded5e7c060d. Report an issue: GitHub.