nautechsystems/nautilus_trader · error · anyhow::Error
invalid type for 'smp_type': {value}, expected string
Error message
invalid type for 'smp_type': {value}, expected string What it means
parse_bybit_tp_sl_params validates optional 'smp_type' entries in a TP/SL params map. The key was present, but the JSON/serde value is not a string, so the parser refuses to interpret it and bails instead of guessing a coercion. The message interpolates the offending value so the caller can see what was passed.
Source
Thrown at crates/adapters/bybit/src/common/parse.rs:1907
if let Some(value) = params.get("order_iv") {
match get_price_str(params, "order_iv") {
Some(s) => result.order_iv = Some(s),
None => {
anyhow::bail!("invalid type for 'order_iv': {value}, expected string or number")
}
}
}
if let Some(value) = params.get("mmp") {
match value.as_bool() {
Some(b) => result.mmp = Some(b),
None => anyhow::bail!("invalid type for 'mmp': {value}, expected bool"),
}
}
if let Some(value) = params.get("smp_type") {
let smp_type = value.as_str().ok_or_else(|| {
anyhow::anyhow!("invalid type for 'smp_type': {value}, expected string")
})?;
result.smp_type = Some(parse_smp_type(smp_type)?);
}
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();View on GitHub (pinned to 18893faf8b)
Solutions
- Pass smp_type as a string (e.g. "None", "Cancel") in the params map
- Coerce numeric/bool config values to strings before calling parse_bybit_tp_sl_params
- Fix the config source (YAML/JSON/env) so smp_type is quoted
Example fix
// before
let params = serde_json::json!({"smp_type": 1});
// after
let params = serde_json::json!({"smp_type": "None"}); Defensive patterns
Strategy: validation
Validate before calling
fn ensure_string_param(params: &serde_json::Value, key: &str) -> anyhow::Result<&str> {
params.get(key)
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow::anyhow!("{key} must be a string"))
} Type guard
fn as_str_param(v: &serde_json::Value) -> Option<&str> {
if v.is_string() { v.as_str() } else { None }
} Try / catch
match parse_bybit_tp_sl_params(¶ms) {
Ok(p) => p,
Err(e) if e.to_string().contains("smp_type") => {
eprintln!("smp_type must be a string: {e}");
Default::default()
}
Err(e) => return Err(e),
} Prevention
- Quote string config values in YAML/JSON
- Build params maps with typed builders instead of raw JSON
- Add a schema check over params keys before parsing
When it happens
Trigger: Passing params["smp_type"] as a non-string JSON value, e.g. an integer 1, a bool, or a nested object, into the Bybit TP/SL params builder.
Common situations: Building the params map from untyped config files, environment variables, or deserialized JSON where the value was not normalized to a string like "None" before calling the parser.
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 'position_idx': {value}, expected integer
- invalid type for 'bbo_side_type': {value}, expected string
- invalid type for 'order_iv': {value}, expected string or num
- invalid type for 'mmp': {value}, expected bool
- invalid type for 'bbo_level': {value}, expected string or in
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c86b7e6652341b71.
Report an issue: GitHub.