{"record":{"id":"ed98e2127b66f665","repo":"nautechsystems/nautilus_trader","slug":"invalid-bybit-tp-sl-mode-s-expected-full-or","errorCode":null,"errorMessage":"invalid Bybit TP/SL mode: '{s}', expected Full or Partial","messagePattern":"invalid Bybit TP/SL mode: '(.+?)', expected Full or Partial","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/common/parse.rs","lineNumber":1979,"sourceCode":"        ),\n    }\n}\n\npub(crate) fn parse_tp_sl_order_type(s: &str) -> anyhow::Result<BybitOrderType> {\n    match s {\n        \"Market\" => Ok(BybitOrderType::Market),\n        \"Limit\" => Ok(BybitOrderType::Limit),\n        _ => anyhow::bail!(\"invalid Bybit TP/SL order type: '{s}', expected Market or Limit\"),\n    }\n}\n\n// A plain `serde_json` deserialize would accept unknown strings: `BybitTpSlMode` carries a\n// `#[serde(other)] Unknown` variant, so garbage would silently map to `Unknown`.\npub(crate) fn parse_tpsl_mode(s: &str) -> anyhow::Result<BybitTpSlMode> {\n    match s {\n        \"Full\" => Ok(BybitTpSlMode::Full),\n        \"Partial\" => Ok(BybitTpSlMode::Partial),\n        _ => anyhow::bail!(\"invalid Bybit TP/SL mode: '{s}', expected Full or Partial\"),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use nautilus_model::{\n        data::BarSpecification,\n        enums::{AggregationSource, BarAggregation, PositionSide, PriceType},\n    };\n    use rstest::rstest;\n    use serde_json::json;\n\n    use super::*;\n    use crate::{\n        common::{\n            enums::{\n                BybitExecType, BybitOrderSide, BybitOrderType, BybitStopOrderType,\n                BybitTriggerDirection,","sourceCodeStart":1961,"sourceCodeEnd":1997,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/common/parse.rs#L1961-L1997","documentation":"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.","triggerScenarios":"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).","commonSituations":"Symbols without TP/SL mode set returning empty or unexpected strings; stale recorded payloads from older Bybit API behavior; hand-written test fixtures.","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"],"exampleFix":"// before\nparse_tpsl_mode(\"\")? // bails\n// after\nparse_tpsl_mode(\"Full\")?","handlingStrategy":"validation","validationCode":"fn is_valid_tpsl_mode(s: &str) -> bool { matches!(s, \"Full\" | \"Partial\") }","typeGuard":"fn valid_tpsl_mode(s: &str) -> Option<BybitTpSlMode> {\n    match s { \"Full\" => Some(BybitTpSlMode::Full), \"Partial\" => Some(BybitTpSlMode::Partial), _ => None }\n}","tryCatchPattern":"match parse_tpsl_mode(raw) {\n    Ok(m) => proceed(m),\n    Err(e) => { log::debug!(\"no/invalid tpSlMode for symbol: {e}\"); skip_tpsl(); }\n}","preventionTips":["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"],"tags":["bybit","parsing","enum-validation","tpsl"],"backgroundTag":"invalid-enum-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}