nautechsystems/nautilus_trader · error
{FAILED}: {e}
Error message
{FAILED}: {e} What it means
LimitOrder::new panics with `Condition failed: {e}` when LimitOrder::new_checked returns an OrderError; the convenience `new` constructor unwraps via unwrap_or_else(|e| panic!(...)). Validations run before constructing the order: check_positive_quantity, check_display_qty, check_time_in_force, and OrderInitialized::new_checked invariants. The `FAILED` constant is `"Condition failed"` from crates/core/src/correctness.rs.
Source
Thrown at crates/model/src/orders/limit.rs:213
expire_time,
post_only,
reduce_only,
quote_quantity,
display_qty,
emulation_trigger,
trigger_instrument_id,
contingency_type,
order_list_id,
linked_order_ids,
parent_order_id,
exec_algorithm_id,
exec_algorithm_params,
exec_spawn_id,
tags,
init_id,
ts_init,
)
.unwrap_or_else(|e| panic!("{FAILED}: {e}"))
}
}
impl Deref for LimitOrder {
type Target = OrderCore;
fn deref(&self) -> &Self::Target {
&self.core
}
}
impl DerefMut for LimitOrder {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.core
}
}
impl PartialEq for LimitOrder {View on GitHub (pinned to 18893faf8b)
Solutions
- Read the OrderError message in the panic text — it names the failed check precisely.
- Use LimitOrder::new_checked instead of new and handle the Result so bad input doesn't panic.
- Fix the inputs: positive quantity, display_qty <= quantity, expire_time set for GTD, valid OrderSide.
- Validate config-derived values before calling the constructor.
Example fix
// before
let order = LimitOrder::new(..., Quantity::from(0), ...); // panics
// after
let order = LimitOrder::new_checked(..., Quantity::from(0), ...)
.inspect_err(|e| log::error!("invalid limit order: {e}"))
.ok(); Defensive patterns
Strategy: validation
Validate before calling
fn valid_limit_args(qty: Quantity, display_qty: Option<Quantity>, tif: TimeInForce, expire_time: Option<UnixNanos>) -> Result<(), String> {
if qty.raw == 0 { return Err("quantity must be positive".into()); }
if let Some(dq) = display_qty { if dq > qty { return Err("display_qty exceeds quantity".into()); } }
if tif == TimeInForce::Gtd && expire_time.map_or(true, |t| t.as_u64() == 0) { return Err("GTD requires expire_time".into()); }
Ok(())
} Type guard
if qty.is_zero() || side == OrderSide::NoOrderSide { return None; } Prevention
- Prefer the *_new_checked constructors at boundaries where inputs may be invalid
- Never pass GTD without expire_time
- Clamp display_qty to quantity
- Add unit tests covering invalid quantity/display_qty/TIF combos
When it happens
Trigger: Calling LimitOrder::new (crates/model/src/orders/limit.rs:159) with: zero or otherwise invalid Quantity, display_qty greater than quantity, TimeInForce::Gtd with None/zero expire_time, or an OrderInitialized invariant violation such as OrderSide::NoOrderSide or invalid contingency/linked_order_ids combination.
Common situations: Building limit orders from user/strategy config where quantity defaulted to zero; setting display_qty (iceberg) larger than total quantity; GTD orders without expire_time after a config refactor; converting an external side enum that maps to NoOrderSide.
Related errors
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c3b9916999debc84.
Report an issue: GitHub.