nautechsystems/nautilus_trader · error

'bbo_side_type' and 'bbo_level' must be provided together

Error message

'bbo_side_type' and 'bbo_level' must be provided together

What it means

Best-bid/offer (BBO) TP/SL configuration is a pair: 'bbo_side_type' describes which side/type and 'bbo_level' the depth level. The parser requires both or neither, bailing when exactly one is present, since a partial BBO spec is meaningless to the exchange.

Source

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

    }

    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(|| {
            anyhow::anyhow!("invalid type for 'bbo_side_type': {value}, expected string")
        })?;
        result.bbo_side_type = Some(parse_bbo_side_type(side_type)?);
    }

    if let Some(value) = params.get("bbo_level") {
        let level = if let Some(s) = value.as_str() {
            s.to_string()
        } else if let Some(i) = value.as_i64() {
            i.to_string()
        } else if let Some(u) = value.as_u64() {
            u.to_string()
        } else {
            anyhow::bail!("invalid type for 'bbo_level': {value}, expected string or integer");

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Provide both 'bbo_side_type' and 'bbo_level' together
  2. Remove both keys if BBO-based TP/SL is not intended
  3. Check the param-building code so both keys are set from the same config section

Example fix

// before
params.set("bbo_side_type", "Bid");
// after
params.set("bbo_side_type", "Bid");
params.set("bbo_level", "1");
Defensive patterns

Strategy: validation

Validate before calling

fn validate_bbo_pair(params: &Params) -> Result<(), String> {
    let has_type = params.get("bbo_side_type").is_some();
    let has_level = params.get("bbo_level").is_some();
    if has_type != has_level {
        return Err("bbo_side_type and bbo_level must be provided together".into());
    }
    Ok(())
}

Type guard

fn has_partial_bbo(params: &Params) -> bool {
    params.get("bbo_side_type").is_some() != params.get("bbo_level").is_some()
}

Try / catch

match parse_bybit_tp_sl_params(&params) {
    Ok(p) => submit(p),
    Err(e) if e.to_string().contains("'bbo_side_type' and 'bbo_level' must be provided together") => {
        log::warn("Partial BBO config; supply both bbo_side_type and bbo_level or neither");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Setting 'bbo_side_type' without 'bbo_level', or 'bbo_level' without 'bbo_side_type', in TP/SL params.

Common situations: Conditionally-built params where only one of the two keys survived a filter; partial config merge that dropped the sibling key.

Related errors


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