{"record":{"id":"0794e919df2d1ae2","repo":"nautechsystems/nautilus_trader","slug":"invalid-bbo-level-s-expected-1-2-3-4-o","errorCode":null,"errorMessage":"invalid 'bbo_level': '{s}', expected 1, 2, 3, 4, or 5","messagePattern":"invalid 'bbo_level': '(.+?)', expected 1, 2, 3, 4, or 5","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/common/parse.rs","lineNumber":1775,"sourceCode":"    let Some(value) = Option::<String>::deserialize(d)? else {\n        return Ok(None);\n    };\n\n    parse_smp_type(&value).map(Some).map_err(D::Error::custom)\n}\n\npub fn parse_bbo_side_type(s: &str) -> anyhow::Result<BybitBboSideType> {\n    match s.to_ascii_lowercase().as_str() {\n        \"queue\" => Ok(BybitBboSideType::Queue),\n        \"counterparty\" => Ok(BybitBboSideType::Counterparty),\n        _ => anyhow::bail!(\"invalid Bybit bbo_side_type: '{s}', expected Queue or Counterparty\"),\n    }\n}\n\npub fn parse_bbo_level(s: String) -> anyhow::Result<String> {\n    match s.as_str() {\n        \"1\" | \"2\" | \"3\" | \"4\" | \"5\" => Ok(s),\n        _ => anyhow::bail!(\"invalid 'bbo_level': '{s}', expected 1, 2, 3, 4, or 5\"),\n    }\n}\n\n/// Parses Bybit TP/SL parameters from an optional params map.\npub fn parse_bybit_tp_sl_params(params: Option<&Params>) -> anyhow::Result<BybitTpSlParams> {\n    let Some(params) = params else {\n        return Ok(BybitTpSlParams::default());\n    };\n\n    let mut result = BybitTpSlParams {\n        is_leverage: params.get_bool(\"is_leverage\").unwrap_or(false),\n        ..Default::default()\n    };\n\n    if let Some(s) = get_price_str(params, \"take_profit\") {\n        let p =\n            Price::from_str(&s).map_err(|e| anyhow::anyhow!(\"invalid 'take_profit' price: {e}\"))?;\n","sourceCodeStart":1757,"sourceCodeEnd":1793,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/common/parse.rs#L1757-L1793","documentation":"parse_bbo_level validates the bbo_level parameter, which selects which of the top 5 BBO levels triggers a TP/SL order. Only the string values '1' through '5' are accepted; any other string raises this anyhow error.","triggerScenarios":"Passing bbo_level in TP/SL params (via parse_bybit_tp_sl_params, reached from order submission) as e.g. '0', '6', 'level3', or an integer-typed value stringified unusually.","commonSituations":"Assuming the level range starts at 0 (programmer habit), requesting a level beyond Bybit's supported top-5 depth, or passing an int instead of a string in Python params.","solutions":["Pass bbo_level as the string '1', '2', '3', '4' or '5'","Clamp your desired level to the 1-5 range before submitting","Omit bbo_level to use the default"],"exampleFix":"// before\nparams.insert(\"bbo_level\", \"0\");\n// after\nparams.insert(\"bbo_level\", \"1\");","handlingStrategy":"validation","validationCode":"assert bbo_level in (\"1\", \"2\", \"3\", \"4\", \"5\"), f\"bbo_level must be 1-5, got {bbo_level}\"","typeGuard":"fn is_valid_bbo_level(s: &str) -> bool {\n    matches!(s.as_str(), \"1\" | \"2\" | \"3\" | \"4\" | \"5\")\n}","tryCatchPattern":"match parse_bbo_level(s) {\n    Ok(l) => use(l),\n    Err(e) => { log::error!(\"{e}\"); use_default_level() }\n}","preventionTips":["Remember levels are 1-based and capped at 5","Pass as a string, not an int, if constructing params manually","Clamp user input to 1..=5 before submitting"],"tags":["bybit","tpsl","bbo","validation","order"],"backgroundTag":"invalid-argument-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"}