nautechsystems/nautilus_trader · error
Order quantity must be positive
Error message
Order quantity must be positive
What it means
quantity_to_raw_amount converts a base-denominated order Quantity into raw token units with exact integer scaling. It rejects a zero quantity outright: a zero-amount order cannot correspond to any valid on-chain swap amount and would produce a useless or reverting transaction.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:2446
anyhow::bail!(
"Input token {} balance {balance} is below the swap amount {}",
plan.token_in,
plan.amount_in
);
}
Ok(())
}
/// Converts a base-denominated order quantity into raw token units with exact integer
/// scaling by the base token decimals.
///
/// `Quantity::raw` is scaled to the greater of its declared precision and `FIXED_PRECISION`;
/// token amounts are scaled to the token's decimals. Quantities not exactly representable in
/// token units are rejected rather than rounded.
fn quantity_to_raw_amount(quantity: Quantity, decimals: u8) -> anyhow::Result<U256> {
if quantity.is_zero() {
anyhow::bail!("Order quantity must be positive");
}
let raw = U256::from(quantity.raw);
let raw_precision = quantity.precision.max(FIXED_PRECISION);
if decimals >= raw_precision {
let scale = U256::from(10u64)
.checked_pow(U256::from(decimals - raw_precision))
.ok_or_else(|| anyhow::anyhow!("Order amount scaling overflow"))?;
raw.checked_mul(scale).ok_or_else(|| {
anyhow::anyhow!("Order amount overflow scaling quantity to raw token units")
})
} else {
let divisor = U256::from(10u64)
.checked_pow(U256::from(raw_precision - decimals))
.ok_or_else(|| anyhow::anyhow!("Order amount scaling overflow"))?;
if !(raw % divisor).is_zero() {
anyhow::bail!(
"Order quantity {quantity} is not exactly representable in {decimals} base token decimals"View on GitHub (pinned to 2114cf6f76)
Solutions
- Skip order submission entirely when the computed size is zero instead of forwarding it to the execution client
- Fix the sizing logic so signals with non-zero intent produce a positive size (guard upstream division/clamping)
- Validate user/config-provided sizes as strictly positive at the boundary where they enter the system
Example fix
// before
let qty = signal_strength * notional; // can be 0.0
submit_order(&instrument, Quantity::from(qty));
// after
let qty = signal_strength * notional;
if qty > 0.0 {
submit_order(&instrument, Quantity::from(qty));
} Defensive patterns
Strategy: validation
Validate before calling
anyhow::ensure!(!qty.is_zero(), "refusing to submit zero-sized order for {instrument_id}");
let amount = quantity_to_raw_amount(qty, decimals)?; Try / catch
match quantity_to_raw_amount(qty, decimals) {
Err(e) if e.to_string().contains("must be positive") => {
// sizing bug upstream: drop the signal and log; never coerce 0 -> 1
log::warn!("zero size from sizer; skipping order");
Ok(None)
}
other => other.map(Some),
} Prevention
- Assert positive size in the strategy's submit path, not just in the executor
- Unit-test sizers for boundary inputs (zero signal, zero capital) expecting no submission
- Treat a zero-size order as a smell: log it with the inputs that produced it
When it happens
Trigger: Passing a Quantity that is zero to the order/swap amount conversion: strategy sizing math that multiplies by a zero factor, a clamp that floors a computed size to zero, Quantity::default()/from('0') used as a placeholder, or a parsed size of 0 from user input or config.
Common situations: Sizing engines that emit zero when capital allocation, signal strength, or available balance computes to zero; order templates with unset size fields; edge-case tests or config presets that accidentally leave size at zero.
Related errors
- AX minimum_order_size must be a positive whole number, was {
- Slippage {slippage_bps} bps must be below {BPS_DENOMINATOR}
- height must be positive, was {self.height}
- pandas is required for report generation; install it with `p
- {name} must not be None
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/7b51c0b66fe1346c.
Report an issue: GitHub.