nautechsystems/nautilus_trader · error

{quantity_field} {quantity} must be positive

Error message

{quantity_field} {quantity} must be positive

What it means

validate_pending_trade_values checks quantity/price pairs for pending target trades before reconciliation. Trade size must be strictly greater than zero; a zero or negative quantity is rejected with this anyhow error, using the caller-supplied field label.

Source

Thrown at crates/adapters/polymarket/src/execution/reconciliation.rs:418

fn validate_trade_values(
    quantity: Decimal,
    price: Decimal,
    size_precision: u8,
    quantity_field: &str,
    price_field: &str,
) -> anyhow::Result<Price> {
    validate_quantity_evidence(quantity, size_precision, quantity_field, false)?;
    validate_historical_price_evidence(price, price_field)
}

fn validate_pending_trade_values(
    quantity: Decimal,
    price: Decimal,
    quantity_field: &str,
    price_field: &str,
) -> anyhow::Result<()> {
    anyhow::ensure!(
        quantity > Decimal::ZERO,
        "{quantity_field} {quantity} must be positive"
    );
    anyhow::ensure!(
        price > Decimal::ZERO && price < Decimal::ONE,
        "{price_field} {price} must be greater than zero and less than one",
    );
    Ok(())
}

fn require_trade_timestamp(
    ts_event: Option<UnixNanos>,
    trade: &PolymarketTradeReport,
) -> anyhow::Result<UnixNanos> {
    ts_event.with_context(|| {
        format!(
            "selected trade {} has invalid match_time {}",
            trade.id, trade.match_time,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Skip orders whose remaining quantity is zero before calling classify_target_trade.
  2. Clamp or early-return when quantity <= 0 with a debug log instead of feeding it into reconciliation.
  3. Fix the upstream computation that yields a negative remaining quantity (typically size - filled with inconsistent units).

Example fix

// before
let remaining = total_size - filled; // can be 0 or negative
validate_pending_trade_values(remaining, price, "remaining_size", "price")?;
// after
let remaining = (total_size - filled).max(Decimal::ZERO);
if remaining.is_zero() { return Ok(None); } // skip fully-filled orders
validate_pending_trade_values(remaining, price, "remaining_size", "price")?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_positive(q: rust_decimal::Decimal) -> bool { q > rust_decimal::Decimal::ZERO }
if !is_positive(remaining) { return Ok(None); } // skip fully-filled/closed trades

Type guard

fn is_valid_pending_qty(q: &rust_decimal::Decimal) -> bool { q.is_sign_positive() && !q.is_zero() }

Try / catch

match classify_target_trade(&order, &evidence) {
    Err(e) if e.to_string().ends_with("must be positive") => Ok(None), // treat as nothing pending
    other => other,
}

Prevention

When it happens

Trigger: classify_target_trade passes a Decimal quantity <= 0 (e.g. remaining size after fills is 0, or a signed subtraction went negative) into validate_pending_trade_values.

Common situations: Fully-filled orders whose computed remaining quantity reaches 0 and are still fed through reconciliation; signed-quantity bugs producing negative pending sizes; provider size fields parsed as 0 for closed markets.

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/11b8766d2d25dd49. Report an issue: GitHub.