nautechsystems/nautilus_trader · error
Order quantity must be at least 1 contract
Error message
Order quantity must be at least 1 contract
What it means
After dividing out the fixed-precision scale, `quantity_to_contracts` rejects a resulting contract count of 0. This catches quantities that are whole but smaller than one contract (e.g. quantity 0, or a fractional value that rounded contextually). AX orders must be at least 1 contract.
Solutions
- Check quantity >= instrument min_quantity (and >= 1 contract) before submitting
- Skip no-op rebalances where the target delta rounds to zero contracts
- Correct strategy sizing logic producing zero/negative order sizes
Example fix
// before
if target_delta != 0.0 { submit(target_delta) }
// after
let contracts = target_delta.floor();
if contracts >= 1.0 { submit(Quantity::new(contracts, 0)) } Defensive patterns
Strategy: validation
Validate before calling
if order.quantity().as_f64() < 1.0 {
return; // skip no-op order
} Try / catch
match quantity_to_contracts(qty) {
Ok(n) if n >= 1 => submit(n),
Ok(_) | Err(_) => log::debug!("quantity below 1 contract, not submitting"),
} Prevention
- Check instrument.min_quantity before every submit
- Ignore rebalance deltas smaller than one contract
- Validate size_increment configuration on instrument load
When it happens
Trigger: submit_order or modify_order called with quantity 0, or any quantity in (0, 1) contracts, through the AX execution client.
Common situations: Strategies computing near-zero target deltas and emitting 0-size orders; min-quantity guard missing before submit; misconfigured size_increment.
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
- AX requires whole contract quantities, was
- missing trigger price for Derive trigger order
- Unsupported order type
- closing quantity was zero
- Empty underlying for
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/99b5c8951a61e339.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/architect_ax/src/common/parse.rs:207
/// - The quantity is zero.
pub fn quantity_to_contracts(quantity: Quantity) -> anyhow::Result<u64> {
let raw = quantity.raw;
let scale = 10_u64.pow(FIXED_PRECISION as u32) as QuantityRaw;
// AX requires whole contract quantities
if !raw.is_multiple_of(scale) {
anyhow::bail!(
"AX requires whole contract quantities, was {}",
quantity.as_f64()
);
}
// QuantityRaw is u128 under the `high-precision` feature and u64 otherwise,
// so the narrowing cast is conditional on the active feature set.
#[allow(clippy::unnecessary_cast)]
let contracts = (raw / scale) as u64;
if contracts == 0 {
anyhow::bail!("Order quantity must be at least 1 contract");
}
Ok(contracts)
}
/// Converts a [`ClientOrderId`] to a deterministic AX `cid` in the non-negative `int64` range.
///
/// Inbound WebSocket `cid` values remain `u64` because venue messages can exceed `int64`.
#[must_use]
pub fn client_order_id_to_cid(client_order_id: &ClientOrderId) -> u64 {
CID_HASHER.hash_one(client_order_id.inner()) & i64::MAX as u64
}
/// Creates a [`ClientOrderId`] from a cid value.
///
/// Used when we receive an order with a cid but cannot resolve it to the
/// original ClientOrderId (e.g., after restart when in-memory mapping is lost).
#[must_use]
pub fn cid_to_client_order_id(cid: u64) -> ClientOrderId {View on GitHub (pinned to 18893faf8b)