nautechsystems/nautilus_trader · error · anyhow::Error
invalid type for 'position_idx': {value}, expected integer
Error message
invalid type for 'position_idx': {value}, expected integer What it means
parse_bybit_tp_sl_params reads the optional 'position_idx' key and requires it to be an integer that maps to a Bybit position index mode. A non-integer value cannot be mapped to OneWay/BuyHedge/SellHedge, so the parser bails with the offending value interpolated.
Source
Thrown at crates/adapters/bybit/src/common/parse.rs:1914
}
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();
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(|| {View on GitHub (pinned to 18893faf8b)
Solutions
- Pass position_idx as an integer 0, 1, or 2
- Unquote the value in the config so it parses as a number
- Validate the key type before calling parse_bybit_tp_sl_params
Example fix
// before
let params = serde_json::json!({"position_idx": "1"});
// after
let params = serde_json::json!({"position_idx": 1}); Defensive patterns
Strategy: validation
Validate before calling
if let Some(v) = params.get("position_idx") {
assert!(v.is_i64(), "position_idx must be an integer, got {v}");
} Type guard
fn as_i64_param(v: &serde_json::Value) -> Option<i64> {
v.as_i64()
} Try / catch
let result = parse_bybit_tp_sl_params(¶ms)
.map_err(|e| e.context("position_idx must be an integer in TP/SL params"))?; Prevention
- Avoid quoting numeric values in configs
- Keep position_idx as a typed integer in your domain model
- Validate the whole params map once at config load time
When it happens
Trigger: Setting params["position_idx"] to a string like "1", a float, or any non-integer JSON value when building Bybit TP/SL params.
Common situations: Config files quoting the number (position_idx: "1"), or generic JSON configs where the field was not typed as a number.
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 'smp_type': {value}, expected string
- 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/f9ad1646f0ee57ff.
Report an issue: GitHub.