nautechsystems/nautilus_trader · error · anyhow::Error
invalid price for '{key}': '{s}'
Error message
invalid price for '{key}': '{s}' What it means
For trigger-price parameters ('tp_trigger_price' and 'sl_trigger_price'), parse_bybit_tp_sl_params parses the string as f64 and rejects values that fail to parse or (in the follow-up check) are non-finite/negative. This specific error fires when the string cannot be parsed as a number at all.
Source
Thrown at crates/adapters/bybit/src/common/parse.rs:1822
if p.as_f64() < 0.0 {
anyhow::bail!("invalid 'stop_loss' price: '{s}', expected a non-negative value");
}
result.stop_loss = Some(p);
}
for (key, setter) in [
(
"tp_limit_price",
&mut result.tp_limit_price as &mut Option<String>,
),
("sl_limit_price", &mut result.sl_limit_price),
("tp_trigger_price", &mut result.tp_trigger_price),
("sl_trigger_price", &mut result.sl_trigger_price),
] {
if let Some(s) = get_price_str(params, key) {
let v: f64 = s
.parse()
.map_err(|_| anyhow::anyhow!("invalid price for '{key}': '{s}'"))?;
if !v.is_finite() || v < 0.0 {
anyhow::bail!(
"invalid price for '{key}': '{s}', expected a finite non-negative number"
);
}
*setter = Some(s);
}
}
if let Some(s) = params.get_str("tp_trigger_by") {
result.tp_trigger_by = Some(parse_trigger_type(s)?);
}
if let Some(s) = params.get_str("sl_trigger_by") {
result.sl_trigger_by = Some(parse_trigger_type(s)?);
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure trigger price params are clean numeric strings, e.g. "65000.5" (trim whitespace, no separators/units).
- Validate with a parse check before submitting: value.parse::<f64>() and confirm finite and >= 0.
- Omit the trigger-price keys when the feature is not used instead of sending empty values.
- Sanitize upstream numeric formatting so no commas or unit suffixes leak into the string.
Example fix
// before
params.insert("sl_trigger_price".into(), trigger_price_input.to_string());
// after
let v: f64 = trigger_price_input.trim().parse()?;
anyhow::ensure!(v.is_finite() && v >= 0.0, "sl_trigger_price must be finite non-negative");
params.insert("sl_trigger_price".into(), format!("{v}")); Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate trigger prices before building order params
fn valid_trigger(s: &str) -> bool {
s.trim().parse::<f64>().map(|v| v.is_finite() && v >= 0.0).unwrap_or(false)
}
if !valid_trigger(&sl_trigger) { anyhow::bail!("bad sl_trigger_price: {sl_trigger}"); } Type guard
fn parse_trigger(s: &str) -> Option<f64> {
s.trim().parse::<f64>().ok().filter(|v| v.is_finite() && *v >= 0.0)
} Try / catch
let p = parse_bybit_tp_sl_params(¶ms)
.inspect_err(|e| log::error!("invalid TP/SL trigger params: {e:#}"))?; Prevention
- Send plain numeric strings with no units, commas, or whitespace
- Only include trigger keys when trigger orders are actually configured
- Unit-test param building with boundary values (0, very small, very large)
When it happens
Trigger: Order params contain 'tp_trigger_price' or 'sl_trigger_price' with a value that f64::from_str rejects — empty string, descriptive text, numbers with units ('65000 USD'), or comma-formatted numbers.
Common situations: Config-driven strategies with placeholder trigger values; strings carrying thousands separators ('65,000.5'); accidentally passing the key with an empty value from a partially-filled UI/config; prior step producing 'NaN'.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- invalid 'take_profit' price: {e}
- invalid 'stop_loss' price: {e}
- invalid price for '{key}': '{s}', expected a finite non-nega
- invalid Bybit trigger type: '{s}', expected LastPrice, MarkP
- invalid Bybit TP/SL order type: '{s}', expected Market or Li
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/6d4558c979188ac6.
Report an issue: GitHub.