nautechsystems/nautilus_trader · error · PyValueError

Invalid BybitPositionIdx value: {int_val}

Error message

Invalid BybitPositionIdx value: {int_val}

What it means

The Python-side BybitPositionIdx.from_str was given an integer other than 0, 1, or 2; those are the only Bybit position-index modes (one-way, buy hedge, sell hedge), so any other integer is rejected with ValueError.

Source

Thrown at crates/adapters/bybit/src/python/enums.rs:363

    pub fn value(&self) -> i32 {
        *self as i32
    }

    #[staticmethod]
    #[must_use]
    fn variants() -> Vec<String> {
        Self::iter().map(|x| x.to_string()).collect()
    }

    #[classmethod]
    #[pyo3(name = "from_str")]
    fn py_from_str(_cls: &Bound<'_, PyType>, data: &Bound<'_, PyAny>) -> PyResult<Self> {
        if let Ok(int_val) = data.extract::<i32>() {
            return match int_val {
                0 => Ok(Self::OneWay),
                1 => Ok(Self::BuyHedge),
                2 => Ok(Self::SellHedge),
                _ => Err(to_pyvalue_err(anyhow::anyhow!(
                    "Invalid BybitPositionIdx value: {int_val}"
                ))),
            };
        }

        let data_str: String = data.str()?.extract()?;
        Self::from_str(&data_str).map_err(to_pyvalue_err)
    }
}

#[pymethods]
#[pyo3_stub_gen::derive::gen_stub_pymethods]
impl BybitMarginAction {
    /// Margin actions for spot margin trading operations.
    #[new]
    fn py_new(py: Python<'_>, value: &Bound<'_, PyAny>) -> PyResult<Self> {
        let t = Self::type_object(py);
        Self::py_from_str(&t, value)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use 0 for one-way mode, 1 for hedge-mode buy side, 2 for hedge-mode sell side
  2. Pass exact variant-name strings: 'OneWay', 'BuyHedge', 'SellHedge'
  3. Verify hedge vs one-way mode on the Bybit account matches the positionIdx being sent

Example fix

// before: mixing up mode and index encodings
idx = BybitPositionIdx.from_str(3)
// after
idx = BybitPositionIdx.from_str(1)  # BuyHedge
Defensive patterns

Strategy: type-guard

Validate before calling

if isinstance(v, int) and v not in (0, 1, 2):
    raise ValueError(f'positionIdx must be 0, 1, or 2, got {v}')

Type guard

def is_valid_position_idx(v) -> bool:
    return v in (0, 1, 2) or str(v) in ('OneWay', 'BuyHedge', 'SellHedge')

Try / catch

try:
    idx = BybitPositionIdx.from_str(raw)
except ValueError as e:
    log.warning('bad positionIdx %r', raw); idx = BybitPositionIdx.OneWay

Prevention

When it happens

Trigger: Deserializing a `positionIdx` value from a Bybit payload that is outside {0,1,2}, or passing a bad string/number to BybitPositionIdx.from_str in Python.

Common situations: Using positionIdx values intended for another exchange; copy-pasting position-mode codes (0/3) into positionIdx; corrupted or fabricated test payloads.

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


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