nautechsystems/nautilus_trader · error · anyhow::Error

invalid type for 'position_idx': {value}, expected integer

Error message

invalid type for 'position_idx': {value}, expected integer

What it means

parse_bybit_tp_sl_params reads the optional 'position_idx' key and requires it to be an integer that maps to a Bybit position index mode. A non-integer value cannot be mapped to OneWay/BuyHedge/SellHedge, so the parser bails with the offending value interpolated.

Source

Thrown at crates/adapters/bybit/src/common/parse.rs:1914

    }

    if let Some(value) = params.get("mmp") {
        match value.as_bool() {
            Some(b) => result.mmp = Some(b),
            None => anyhow::bail!("invalid type for 'mmp': {value}, expected bool"),
        }
    }

    if let Some(value) = params.get("smp_type") {
        let smp_type = value.as_str().ok_or_else(|| {
            anyhow::anyhow!("invalid type for 'smp_type': {value}, expected string")
        })?;
        result.smp_type = Some(parse_smp_type(smp_type)?);
    }

    if let Some(value) = params.get("position_idx") {
        let idx = value.as_i64().ok_or_else(|| {
            anyhow::anyhow!("invalid type for 'position_idx': {value}, expected integer")
        })?;
        result.position_idx = Some(match idx {
            0 => BybitPositionIdx::OneWay,
            1 => BybitPositionIdx::BuyHedge,
            2 => BybitPositionIdx::SellHedge,
            _ => anyhow::bail!("invalid 'position_idx': {idx}, expected 0, 1, or 2"),
        });
    }

    let has_bbo_side_type = params.get("bbo_side_type").is_some();
    let has_bbo_level = params.get("bbo_level").is_some();

    if has_bbo_side_type != has_bbo_level {
        anyhow::bail!("'bbo_side_type' and 'bbo_level' must be provided together");
    }

    if let Some(value) = params.get("bbo_side_type") {
        let side_type = value.as_str().ok_or_else(|| {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pass position_idx as an integer 0, 1, or 2
  2. Unquote the value in the config so it parses as a number
  3. Validate the key type before calling parse_bybit_tp_sl_params

Example fix

// before
let params = serde_json::json!({"position_idx": "1"});
// after
let params = serde_json::json!({"position_idx": 1});
Defensive patterns

Strategy: validation

Validate before calling

if let Some(v) = params.get("position_idx") {
    assert!(v.is_i64(), "position_idx must be an integer, got {v}");
}

Type guard

fn as_i64_param(v: &serde_json::Value) -> Option<i64> {
    v.as_i64()
}

Try / catch

let result = parse_bybit_tp_sl_params(&params)
    .map_err(|e| e.context("position_idx must be an integer in TP/SL params"))?;

Prevention

When it happens

Trigger: Setting params["position_idx"] to a string like "1", a float, or any non-integer JSON value when building Bybit TP/SL params.

Common situations: Config files quoting the number (position_idx: "1"), or generic JSON configs where the field was not typed as a number.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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