nautechsystems/nautilus_trader · error

initial_margin_fraction must be in 1..=10_000, was {initial_

Error message

initial_margin_fraction must be in 1..=10_000, was {initial_margin_fraction}

What it means

Lighter's initial_margin_fraction is expressed in basis-point-like units and must be between 1 and 10,000 inclusive (i.e. leverage between 10,000x and 1x). update_leverage validates the requested value up front and rejects anything outside that range.

Source

Thrown at crates/adapters/lighter/src/execution.rs:2083

    /// Returns an error if credentials are missing, the instrument is not
    /// registered, `initial_margin_fraction` is outside `1..=10_000`, or
    /// the dispatch pre-flight (nonce allocation, signing) fails. Transport
    /// errors after dispatch are logged but not returned synchronously.
    pub fn update_leverage(
        &self,
        instrument_id: InstrumentId,
        initial_margin_fraction: u16,
        margin_mode: LighterPositionMarginMode,
    ) -> anyhow::Result<()> {
        let credential = self.credential.as_ref().ok_or_else(|| {
            anyhow::anyhow!("Lighter execution client cannot update leverage without credentials")
        })?;

        let market_index = self.registry.market_index(&instrument_id).ok_or_else(|| {
            anyhow::anyhow!("no Lighter market_index registered for instrument {instrument_id}")
        })?;

        anyhow::ensure!(
            (1..=10_000).contains(&initial_margin_fraction),
            "initial_margin_fraction must be in 1..=10_000, was {initial_margin_fraction}",
        );

        let ReservedTxContext {
            context,
            mut send_reservation,
        } = self.build_tx_context(credential)?;

        let connection_epoch = send_reservation.connection_epoch;

        let captured_nonce = context.nonce;
        let captured_api_key_index = context.api_key_index;
        let mut rollback_guard =
            TxDispatchGuard::new(self.dispatch.clone(), credential, None, captured_nonce);

        let tx = UpdateLeverageTxInfo {
            context,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Convert leverage to margin fraction: initial_margin_fraction = 10_000 / leverage (e.g. 20x -> 500).
  2. Clamp/validate the value into 1..=10_000 before calling update_leverage.
  3. If you meant to raise leverage, decrease the fraction, not increase it.

Example fix

// before
client.update_leverage(iid, 25 /* intended 25x */, mode).await?; // out of range semantics
// after
let imf = (10_000 / leverage).clamp(1, 10_000);
client.update_leverage(iid, imf, mode).await?;
Defensive patterns

Strategy: validation

Validate before calling

let imf = 10_000u32.checked_div(leverage).ok_or("leverage must be >= 1")?;
assert!((1..=10_000).contains(&imf), "imf {imf} out of 1..=10_000");

Try / catch

if let Err(e) = client.update_leverage(iid, imf, mode).await {
    if e.to_string().contains("initial_margin_fraction must be") {
        let clamped = imf.clamp(1, 10_000);
        client.update_leverage(iid, clamped, mode).await?;
    }
}

Prevention

When it happens

Trigger: update_leverage called with initial_margin_fraction of 0, negative (if passed as a wider integer), or > 10,000 — e.g. passing a percentage like 50 meaning 50% but which is actually valid only via inverse units, or confusing this field with leverage multiplier.

Common situations: Passing leverage (e.g. 20) where the API wants margin fraction, or margin fraction 0.05 where an integer 1..=10_000 is expected; copy-pasted defaults from another exchange adapter; UI sending percent values.

Related errors


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