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
- Log/inspect the raw tpSlMode value in the payload
- Use a symbol that has TP/SL configured so Bybit returns Full or Partial
- Update the adapter if Bybit introduced a new mode
- 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
- Remember symbols without TP/SL set may return empty mode — guard for it
- Use typed enums rather than raw strings in client code
- Avoid replaying stale recorded payloads across API versions
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
- invalid Bybit trigger type: '{s}', expected LastPrice, MarkP
- invalid Bybit TP/SL order type: '{s}', expected Market or Li
- invalid Bybit bbo_side_type: '{s}', expected Queue or Counte
- invalid 'bbo_level': '{s}', expected 1, 2, 3, 4, or 5
- invalid 'take_profit' price: '{s}', expected a non-negative
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ed98e2127b66f665.
Report an issue: GitHub.