nautechsystems/nautilus_trader · error

invalid Bybit trigger type

Error message

invalid Bybit trigger type: '{s}', expected LastPrice, MarkPrice, or IndexPrice

What it means

The Bybit adapter validates the trigger price type reported by Bybit when parsing TP/SL (take-profit/stop-loss) parameters from an exchange response. Bybit only defines three trigger types — LastPrice, MarkPrice, IndexPrice — and any other string means an unrecognized/changed exchange payload. The adapter fails fast rather than guessing, so invalid data cannot silently corrupt order state.

Solutions

  1. Check the raw Bybit payload and confirm the triggerBy value it actually contains
  2. Upgrade the nautilus Bybit adapter to a version that maps the new trigger type
  3. Normalize/mutate the value to one of the three supported strings before feeding parse_bybit_tp_sl_params
  4. If the value is legitimately new, extend the match in parse_trigger_type and open/track an adapter update

Example fix

// before
let tt = parse_trigger_type("last_price")?; // fails
// after
let tt = parse_trigger_type("LastPrice")?; // exact Bybit casing
Defensive patterns

Strategy: validation

Validate before calling

const TRIGGER_TYPES: [&str; 3] = ["LastPrice", "MarkPrice", "IndexPrice"];
fn is_valid_trigger(s: &str) -> bool { TRIGGER_TYPES.contains(&s) }

Type guard

fn valid_trigger(s: &str) -> Option<BybitTriggerType> {
    match s {
        "LastPrice" => Some(BybitTriggerType::LastPrice),
        "MarkPrice" => Some(BybitTriggerType::MarkPrice),
        "IndexPrice" => Some(BybitTriggerType::IndexPrice),
        _ => None,
    }
}

Try / catch

match parse_trigger_type(raw) {
    Ok(tt) => proceed(tt),
    Err(e) => { log::warn!("unsupported trigger type, skipping TPSL params: {e}"); fallback(); }
}

Prevention

When it happens

Trigger: Calling parse_bybit_tp_sl_params on a Bybit API response whose triggerBy / tpOrderType trigger field contains a value other than LastPrice, MarkPrice, or IndexPrice (e.g. a new exchange value, a localized payload, or garbage from a mock).

Common situations: Bybit introduces a new trigger type in a API version not yet supported by this adapter version; unit tests or mocks hand-crafting TPSL JSON with typo'd values like 'last_price'; replaying recorded payloads from a different Bybit product line.

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/b7d32f4f89ac82a7. Report an issue: GitHub.

Appendix: source

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

        } 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");
        };
        result.bbo_level = Some(parse_bbo_level(level)?);
    }

    Ok(result)
}

pub(crate) fn parse_trigger_type(s: &str) -> anyhow::Result<BybitTriggerType> {
    match s {
        "LastPrice" => Ok(BybitTriggerType::LastPrice),
        "MarkPrice" => Ok(BybitTriggerType::MarkPrice),
        "IndexPrice" => Ok(BybitTriggerType::IndexPrice),
        _ => anyhow::bail!(
            "invalid Bybit trigger type: '{s}', expected LastPrice, MarkPrice, or IndexPrice"
        ),
    }
}

pub(crate) fn parse_tp_sl_order_type(s: &str) -> anyhow::Result<BybitOrderType> {
    match s {
        "Market" => Ok(BybitOrderType::Market),
        "Limit" => Ok(BybitOrderType::Limit),
        _ => anyhow::bail!("invalid Bybit TP/SL order type: '{s}', expected Market or Limit"),
    }
}

// A plain `serde_json` deserialize would accept unknown strings: `BybitTpSlMode` carries a
// `#[serde(other)] Unknown` variant, so garbage would silently map to `Unknown`.
pub(crate) fn parse_tpsl_mode(s: &str) -> anyhow::Result<BybitTpSlMode> {
    match s {
        "Full" => Ok(BybitTpSlMode::Full),

View on GitHub (pinned to 18893faf8b)