nautechsystems/nautilus_trader · error
invalid 'stop_loss' price: '{s}', expected a non-negative va
Error message
invalid 'stop_loss' price: '{s}', expected a non-negative value What it means
parse_bybit_tp_sl_params converts the stop_loss string to a Price and rejects negative values with this anyhow error. It fires only for parseable but negative prices; malformed strings fail earlier with the 'invalid stop_loss price: {e}' message.
Source
Thrown at crates/adapters/bybit/src/common/parse.rs:1805
..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 = s
.parse()
.map_err(|_| anyhow::anyhow!("invalid price for '{key}': '{s}'"))?;
View on GitHub (pinned to 18893faf8b)
Solutions
- Fix the stop-loss computation so the absolute price is non-negative
- Validate the sign before attaching stop_loss to order params
- Express direction via the order side, not a negative price
Example fix
// before
params.insert("stop_loss", "-2500.5");
// after
params.insert("stop_loss", "2500.5"); Defensive patterns
Strategy: validation
Validate before calling
sl = float(params["stop_loss"])
assert sl >= 0, f"stop_loss must be non-negative, got {sl}" Type guard
fn is_non_negative_price(s: &str) -> bool {
Price::from_str(s).map(|p| p.as_f64() >= 0.0).unwrap_or(false)
} Try / catch
match parse_bybit_tp_sl_params(Some(¶ms)) {
Ok(p) => submit(p),
Err(e) => { log::error!("TP/SL params rejected: {e}"); reject_order_before_exchange() }
} Prevention
- Validate stop-loss is a positive absolute price before submission
- Avoid computing stops as negative deltas
- Cover stop-price math with regression tests
When it happens
Trigger: Submitting an order with params stop_loss='-1.5' (or any negative numeric string) through py_submit_order / place_order with SL attached.
Common situations: Computing stop prices as negative deltas, sign errors in risk calculations, or copying formatted values that include a minus sign.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- invalid 'take_profit' price: '{s}', expected a non-negative
- invalid 'bbo_level': '{s}', expected 1, 2, 3, 4, or 5
- invalid price for '{key}': '{s}', expected a finite non-nega
- TP override fields require 'take_profit' to be set
- invalid Bybit bbo_side_type: '{s}', expected Queue or Counte
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1a25f32752322e82.
Report an issue: GitHub.