nautechsystems/nautilus_trader · error
invalid type for 'bbo_level': {value}, expected string or in
Error message
invalid type for 'bbo_level': {value}, expected string or integer What it means
The 'bbo_level' value must be a string or an integer (i64/u64) so it can be normalized to a level string and parsed via parse_bbo_level. Any other JSON type (float, bool, null, object) triggers this bail with the offending value in the message.
Source
Thrown at crates/adapters/bybit/src/common/parse.rs:1946
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");
};
result.bbo_level = Some(parse_bbo_level(level)?);
}
Ok(result)
}
pub(crate) fn parse_trigger_type(s: &str) -> anyhow::Result<BybitTriggerType> {
match s {
"LastPrice" => Ok(BybitTriggerType::LastPrice),
"MarkPrice" => Ok(BybitTriggerType::MarkPrice),
"IndexPrice" => Ok(BybitTriggerType::IndexPrice),
_ => anyhow::bail!(
"invalid Bybit trigger type: '{s}', expected LastPrice, MarkPrice, or IndexPrice"
),
}
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Pass 'bbo_level' as a string (e.g. "1") or a JSON integer
- Ensure the config source emits whole numbers, not floats, for bbo_level
- Check that the value also passes parse_bbo_level (valid level format) after fixing the type
Example fix
// before
params.set("bbo_level", 1.5);
// after
params.set("bbo_level", "1"); Defensive patterns
Strategy: type-guard
Validate before calling
fn validate_bbo_level(params: &Params) -> Result<(), String> {
if let Some(v) = params.get("bbo_level") {
if !(v.is_string() || v.is_i64() || v.is_u64()) {
return Err(format!("bbo_level must be string or integer, got {v}"));
}
}
Ok(())
} Type guard
fn is_bbo_level_like(v: &Value) -> bool {
v.is_string() || v.is_i64() || v.is_u64()
} Try / catch
match parse_bybit_tp_sl_params(¶ms) {
Ok(p) => submit(p),
Err(e) if e.to_string().contains("invalid type for 'bbo_level'") => {
log::warn("bbo_level must be a string or integer, not a float/bool/null");
}
Err(e) => return Err(e),
} Prevention
- Emit bbo_level as an integer or string, never a float
- Configure YAML/JSON parsers to keep whole numbers as ints
- Pre-validate the value against the level format expected by parse_bbo_level
When it happens
Trigger: Passing 'bbo_level' as a float (e.g. 1.5), bool, null, or nested value while 'bbo_side_type' is also present.
Common situations: YAML/JSON config where the level was parsed as a float; untyped deserialization producing f64 for whole numbers.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- invalid type for 'order_iv': {value}, expected string or num
- invalid type for 'mmp': {value}, expected bool
- 'bbo_side_type' and 'bbo_level' must be provided together
- invalid Bybit bbo_side_type: '{s}', expected Queue or Counte
- invalid 'bbo_level': '{s}', expected 1, 2, 3, 4, or 5
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/12c1f300f6e4d80c.
Report an issue: GitHub.