nautechsystems/nautilus_trader · error · anyhow::Error

Take profit sell trigger_price ({trigger_price}) must be >=

Error message

Take profit sell trigger_price ({trigger_price}) must be >= limit price ({price})

What it means

The dYdX adapter validates conditional (take-profit) orders before submitting them. For a take-profit SELL, the trigger price must be at or above the limit price, otherwise the order could never fill sensibly; validate_conditional_order bails with anyhow when this invariant is violated.

Source

Thrown at crates/adapters/dydx/src/http/parse.rs:271

                }
                OrderSide::Sell if trigger_price > price => {
                    anyhow::bail!(
                        "Stop sell trigger_price ({trigger_price}) must be <= limit price ({price})"
                    );
                }
                _ => {}
            }
        }
        DydxOrderType::TakeProfitLimit | DydxOrderType::TakeProfitMarket => {
            // Take profit: trigger when price rises (sell) or falls (buy)
            match side {
                OrderSide::Buy if trigger_price > price => {
                    anyhow::bail!(
                        "Take profit buy trigger_price ({trigger_price}) must be <= limit price ({price})"
                    );
                }
                OrderSide::Sell if trigger_price < price => {
                    anyhow::bail!(
                        "Take profit sell trigger_price ({trigger_price}) must be >= limit price ({price})"
                    );
                }
                _ => {}
            }
        }
        _ => {}
    }

    Ok(())
}

/// Parses a dYdX perpetual market into a Nautilus [`InstrumentAny`].
///
/// dYdX v4 only supports perpetual markets, so this function creates a
/// [`CryptoPerpetual`] instrument with the appropriate fields mapped from
/// the dYdX market definition.
///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure trigger_price >= price for sell-side take-profit orders before calling the API.
  2. If you actually want trigger below the limit for a sell, you need a stop-limit (OrderSide::Sell stop) not a take-profit.
  3. Swap prices or fix the side if you accidentally built a sell TP with buy semantics (buy requires trigger <= price).

Example fix

// before
let trigger = price!(100);
let limit = price!(110);
validate_conditional_order(OrderSide::Sell, trigger, limit)?;
// after
let trigger = price!(120); // sell TP: trigger must be >= limit
validate_conditional_order(OrderSide::Sell, trigger, limit)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_take_profit(side: OrderSide, trigger: Price, limit: Price) -> bool {
    match side {
        OrderSide::Buy => trigger <= limit,
        OrderSide::Sell => trigger >= limit,
        _ => false,
    }
}
if !is_valid_take_profit(side, trigger_price, price) { return Err(/* fix before submit */); }

Try / catch

match validate_conditional_order(side, trigger, limit) {
    Ok(()) => submit(order),
    Err(e) => log::warn!("conditional order rejected: {e}"), // adjust trigger/limit
}

Prevention

When it happens

Trigger: Calling validate_conditional_order (or submitting a TAKE_PROFIT limit order through the dYdX adapter) with OrderSide::Sell and trigger_price < price. Note the buy case has the mirror-image rule (trigger <= limit).

Common situations: Computing the trigger from a percentage move but forgetting the limit price uses a different reference; mixing up buy/sell TP rules; hardcoding prices in tests or configs; sign conventions from another venue carried over to dYdX.

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


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