nautechsystems/nautilus_trader · error
'bbo_side_type' and 'bbo_level' must be provided together
Error message
'bbo_side_type' and 'bbo_level' must be provided together
What it means
Best-bid/offer (BBO) TP/SL configuration is a pair: 'bbo_side_type' describes which side/type and 'bbo_level' the depth level. The parser requires both or neither, bailing when exactly one is present, since a partial BBO spec is meaningless to the exchange.
Source
Thrown at crates/adapters/bybit/src/common/parse.rs:1928
}
if let Some(value) = params.get("position_idx") {
let idx = value.as_i64().ok_or_else(|| {
anyhow::anyhow!("invalid type for 'position_idx': {value}, expected integer")
})?;
result.position_idx = Some(match idx {
0 => BybitPositionIdx::OneWay,
1 => BybitPositionIdx::BuyHedge,
2 => BybitPositionIdx::SellHedge,
_ => anyhow::bail!("invalid 'position_idx': {idx}, expected 0, 1, or 2"),
});
}
let has_bbo_side_type = params.get("bbo_side_type").is_some();
let has_bbo_level = params.get("bbo_level").is_some();
if has_bbo_side_type != has_bbo_level {
anyhow::bail!("'bbo_side_type' and 'bbo_level' must be provided together");
}
if let Some(value) = params.get("bbo_side_type") {
let side_type = value.as_str().ok_or_else(|| {
anyhow::anyhow!("invalid type for 'bbo_side_type': {value}, expected string")
})?;
result.bbo_side_type = Some(parse_bbo_side_type(side_type)?);
}
if let Some(value) = params.get("bbo_level") {
let level = if let Some(s) = value.as_str() {
s.to_string()
} else if let Some(i) = value.as_i64() {
i.to_string()
} else if let Some(u) = value.as_u64() {
u.to_string()
} else {
anyhow::bail!("invalid type for 'bbo_level': {value}, expected string or integer");View on GitHub (pinned to 18893faf8b)
Solutions
- Provide both 'bbo_side_type' and 'bbo_level' together
- Remove both keys if BBO-based TP/SL is not intended
- Check the param-building code so both keys are set from the same config section
Example fix
// before
params.set("bbo_side_type", "Bid");
// after
params.set("bbo_side_type", "Bid");
params.set("bbo_level", "1"); Defensive patterns
Strategy: validation
Validate before calling
fn validate_bbo_pair(params: &Params) -> Result<(), String> {
let has_type = params.get("bbo_side_type").is_some();
let has_level = params.get("bbo_level").is_some();
if has_type != has_level {
return Err("bbo_side_type and bbo_level must be provided together".into());
}
Ok(())
} Type guard
fn has_partial_bbo(params: &Params) -> bool {
params.get("bbo_side_type").is_some() != params.get("bbo_level").is_some()
} Try / catch
match parse_bybit_tp_sl_params(¶ms) {
Ok(p) => submit(p),
Err(e) if e.to_string().contains("'bbo_side_type' and 'bbo_level' must be provided together") => {
log::warn("Partial BBO config; supply both bbo_side_type and bbo_level or neither");
}
Err(e) => return Err(e),
} Prevention
- Set both BBO keys from a single config section or struct
- Never filter params keys independently when they form a pair
- Add a config-load assertion that bbo_side_type and bbo_level co-occur
When it happens
Trigger: Setting 'bbo_side_type' without 'bbo_level', or 'bbo_level' without 'bbo_side_type', in TP/SL params.
Common situations: Conditionally-built params where only one of the two keys survived a filter; partial config merge that dropped the sibling key.
Related errors
- invalid type for 'bbo_level': {value}, expected string or in
- invalid Bybit bbo_side_type: '{s}', expected Queue or Counte
- invalid 'bbo_level': '{s}', expected 1, 2, 3, 4, or 5
- SL override fields require 'stop_loss' to be set
- 'tp_order_type' is 'Limit' but 'tp_limit_price' was not prov
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/4ad51356c5c19eb4.
Report an issue: GitHub.