nautechsystems/nautilus_trader · error · anyhow::Error
invalid 'stop_loss' price: {e}
Error message
invalid 'stop_loss' price: {e} What it means
parse_bybit_tp_sl_params reads an optional 'stop_loss' param from the order params map and parses it into a Price via Price::from_str; unparseable values raise this error (negative values are rejected separately). It means the stop-loss value supplied is not a valid price string.
Source
Thrown at crates/adapters/bybit/src/common/parse.rs:1802
let mut result = BybitTpSlParams {
is_leverage: params.get_bool("is_leverage").unwrap_or(false),
..Default::default()
};
if let Some(s) = get_price_str(params, "take_profit") {
let p =
Price::from_str(&s).map_err(|e| anyhow::anyhow!("invalid 'take_profit' price: {e}"))?;
if p.as_f64() < 0.0 {
anyhow::bail!("invalid 'take_profit' price: '{s}', expected a non-negative value");
}
result.take_profit = Some(p);
}
if let Some(s) = get_price_str(params, "stop_loss") {
let p =
Price::from_str(&s).map_err(|e| anyhow::anyhow!("invalid 'stop_loss' price: {e}"))?;
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 = sView on GitHub (pinned to 18893faf8b)
Solutions
- Ensure stop_loss is a valid decimal price string with decimals fitting the instrument's price precision.
- Omit the key entirely when no stop-loss is intended instead of passing empty/placeholder values.
- Validate the price is finite and positive before adding to params.
- Format floats explicitly (fixed-point, e.g. {:.8g} or precision-aware) rather than relying on default Display of f64.
Example fix
// before
params.insert("stop_loss".into(), sl.to_string()); // f64, may be 0.0 or NaN
// after
if let Some(sl) = sl.filter(|v| v.is_finite() && *v > 0.0) {
params.insert("stop_loss".into(), format!("{:.2}", sl));
} Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate stop_loss param before building order
let sl = sl.filter(|v| v.is_finite() && *v > 0.0)
.map(|v| format!("{v:.instrument_price_precision$}")); Type guard
fn valid_sl_string(s: &str) -> bool {
s.trim().parse::<f64>().map(|v| v.is_finite() && v > 0.0).unwrap_or(false)
} Try / catch
let p = parse_bybit_tp_sl_params(¶ms)
.map_err(|e| { log::error!("bad stop_loss/TP params: {e:#}"); e })?; Prevention
- Don't send sentinel values (0, -1) as stop prices; omit the key instead
- Format stop prices with fixed-point notation, never default f64 Display
- Verify price fits instrument precision before submission
When it happens
Trigger: Submitting/modifying an order with params['stop_loss'] set to an empty string, non-numeric text, NaN/inf, or a value violating Price parsing rules (e.g. too many decimals for precision).
Common situations: Hardcoded placeholder stop-losses in config; float formatting producing scientific notation for very small prices; strategy passing sentinel values like 0 or -1 meant to mean 'no stop'; locale-formatted numbers.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- invalid 'take_profit' price: {e}
- invalid price for '{key}': '{s}'
- invalid 'stop_loss' price: '{s}', expected a non-negative va
- SL override fields require 'stop_loss' to be set
- 'sl_order_type' is 'Limit' but 'sl_limit_price' was not prov
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ac2df5a1d55a60c1.
Report an issue: GitHub.