{"record":{"id":"9d98c790f04708c6","repo":"nautechsystems/nautilus_trader","slug":"sl-override-fields-require-stop-loss-to-be-set","errorCode":null,"errorMessage":"SL override fields require 'stop_loss' to be set","messagePattern":"SL override fields require 'stop_loss' to be set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/common/parse.rs","lineNumber":1868,"sourceCode":"        result.tpsl_mode = Some(parse_tpsl_mode(s)?);\n    }\n\n    let has_tp_fields = result.tp_trigger_by.is_some()\n        || result.tp_order_type.is_some()\n        || result.tp_limit_price.is_some()\n        || result.tp_trigger_price.is_some();\n\n    let has_sl_fields = result.sl_trigger_by.is_some()\n        || result.sl_order_type.is_some()\n        || result.sl_limit_price.is_some()\n        || result.sl_trigger_price.is_some();\n\n    if result.take_profit.is_none() && has_tp_fields {\n        anyhow::bail!(\"TP override fields require 'take_profit' to be set\");\n    }\n\n    if result.stop_loss.is_none() && has_sl_fields {\n        anyhow::bail!(\"SL override fields require 'stop_loss' to be set\");\n    }\n\n    if result.tp_order_type == Some(BybitOrderType::Limit) && result.tp_limit_price.is_none() {\n        anyhow::bail!(\"'tp_order_type' is 'Limit' but 'tp_limit_price' was not provided\");\n    }\n\n    if result.sl_order_type == Some(BybitOrderType::Limit) && result.sl_limit_price.is_none() {\n        anyhow::bail!(\"'sl_order_type' is 'Limit' but 'sl_limit_price' was not provided\");\n    }\n\n    if result.tp_limit_price.is_some() && result.tp_order_type != Some(BybitOrderType::Limit) {\n        anyhow::bail!(\"'tp_limit_price' requires 'tp_order_type' to be 'Limit'\");\n    }\n\n    if result.sl_limit_price.is_some() && result.sl_order_type != Some(BybitOrderType::Limit) {\n        anyhow::bail!(\"'sl_limit_price' requires 'sl_order_type' to be 'Limit'\");\n    }\n","sourceCodeStart":1850,"sourceCodeEnd":1886,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/common/parse.rs#L1850-L1886","documentation":"parse_bybit_tp_sl_params validates SL/TP override params before building the Bybit tpsl-mode order payload. If any stop-loss override field (e.g. sl_order_type, sl_limit_price, sl_trigger_price) is present in the Params but no 'stop_loss' value itself was set, the parser bails because override fields are meaningless without the SL price they modify.","triggerScenarios":"Calling the TP/SL params parser with params containing keys like 'sl_order_type' or 'sl_limit_price' while 'stop_loss' is absent or None.","commonSituations":"Building a TP/SL modify request where the developer sets the SL order type or limit price but forgets to pass the stop_loss price; template/config-driven params where stop_loss is dropped by an upstream filter.","solutions":["Pass a 'stop_loss' value in the params alongside any 'sl_*' override fields","If the SL override fields were added unintentionally, remove them from params","Check upstream code that constructs the Params to ensure stop_loss is not filtered out or renamed"],"exampleFix":"// before\nlet params = Params::new()\n    .set(\"sl_order_type\", \"Limit\")\n    .set(\"sl_limit_price\", \"41000\");\n// after\nlet params = Params::new()\n    .set(\"stop_loss\", \"42000\")\n    .set(\"sl_order_type\", \"Limit\")\n    .set(\"sl_limit_price\", \"41000\");","handlingStrategy":"validation","validationCode":"fn validate_sl_params(params: &Params) -> Result<(), String> {\n    let has_sl_fields = [\"sl_order_type\", \"sl_limit_price\", \"sl_trigger_price\"]\n        .iter().any(|k| params.get(k).is_some());\n    if has_sl_fields && params.get(\"stop_loss\").is_none() {\n        return Err(\"SL override fields present but 'stop_loss' missing\".into());\n    }\n    Ok(())\n}","typeGuard":"fn requires_stop_loss(params: &Params) -> bool {\n    [\"sl_order_type\", \"sl_limit_price\", \"sl_trigger_price\"]\n        .iter().any(|k| params.get(k).is_some())\n}","tryCatchPattern":"match parse_bybit_tp_sl_params(&params) {\n    Ok(p) => submit(p),\n    Err(e) if e.to_string().contains(\"'stop_loss' to be set\") => {\n        log::warn(\"SL override fields without stop_loss; supply stop_loss or drop sl_* fields\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always set 'stop_loss' whenever any 'sl_*' override key is present","Build SL/TP params from a single struct so related keys travel together","Unit-test param builders for paired required fields"],"tags":["bybit","params-validation","stop-loss"],"backgroundTag":"missing-required-argument","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"}