nautechsystems/nautilus_trader · error

invalid Bybit TP/SL mode: '{s}', expected Full or Partial

Error message

invalid Bybit TP/SL mode: '{s}', expected Full or Partial

What it means

Bybit TP/SL mode can only be "Full" or "Partial"; the adapter parses this field explicitly because the BybitTpSlMode enum has a #[serde(other)] Unknown variant that would otherwise silently swallow garbage values. This bail guarantees malformed or new exchange values surface as an error.

Source

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

        ),
    }
}

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),
        "Partial" => Ok(BybitTpSlMode::Partial),
        _ => anyhow::bail!("invalid Bybit TP/SL mode: '{s}', expected Full or Partial"),
    }
}

#[cfg(test)]
mod tests {
    use nautilus_model::{
        data::BarSpecification,
        enums::{AggregationSource, BarAggregation, PositionSide, PriceType},
    };
    use rstest::rstest;
    use serde_json::json;

    use super::*;
    use crate::{
        common::{
            enums::{
                BybitExecType, BybitOrderSide, BybitOrderType, BybitStopOrderType,
                BybitTriggerDirection,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log/inspect the raw tpSlMode value in the payload
  2. Use a symbol that has TP/SL configured so Bybit returns Full or Partial
  3. Update the adapter if Bybit introduced a new mode
  4. Fix test/mock fixtures to use exact "Full"/"Partial" strings

Example fix

// before
parse_tpsl_mode("")? // bails
// after
parse_tpsl_mode("Full")?
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_tpsl_mode(s: &str) -> bool { matches!(s, "Full" | "Partial") }

Type guard

fn valid_tpsl_mode(s: &str) -> Option<BybitTpSlMode> {
    match s { "Full" => Some(BybitTpSlMode::Full), "Partial" => Some(BybitTpSlMode::Partial), _ => None }
}

Try / catch

match parse_tpsl_mode(raw) {
    Ok(m) => proceed(m),
    Err(e) => { log::debug!("no/invalid tpSlMode for symbol: {e}"); skip_tpsl(); }
}

Prevention

When it happens

Trigger: parse_bybit_tp_sl_params processes a response whose tpSlMode field is not exactly "Full" or "Partial" (e.g. an unset field serialized as "", a typo, or an exchange-side addition).

Common situations: Symbols without TP/SL mode set returning empty or unexpected strings; stale recorded payloads from older Bybit API behavior; hand-written test fixtures.

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