nautechsystems/nautilus_trader · error

{field} {value} must be positive

Error message

{field} {value} must be positive

What it means

validate_quantity_evidence requires strictly positive decimals when allow_zero is false. This error fires when a required quantity field (e.g. an order size or trade amount that must be > 0) is zero or negative.

Source

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

        "provider outcome {outcome} does not match instrument outcome {instrument_outcome}",
    );

    Ok(())
}

fn validate_quantity_evidence(
    value: Decimal,
    precision: u8,
    field: &str,
    allow_zero: bool,
) -> anyhow::Result<()> {
    if allow_zero {
        anyhow::ensure!(
            value >= Decimal::ZERO,
            "{field} {value} must be non-negative"
        );
    } else {
        anyhow::ensure!(value > Decimal::ZERO, "{field} {value} must be positive");
    }

    let quantity = Quantity::from_decimal_dp(value, precision).with_context(|| {
        format!("failed to represent {field} {value} with quantity precision {precision}")
    })?;
    anyhow::ensure!(
        quantity.as_decimal() == value,
        "{field} {value} is not exactly representable with quantity precision {precision}",
    );
    Ok(())
}

fn validate_price_evidence(value: Decimal, precision: u8, field: &str) -> anyhow::Result<()> {
    anyhow::ensure!(
        value > Decimal::ZERO && value < Decimal::ONE,
        "{field} {value} must be greater than zero and less than one",
    );
    let price = Price::from_decimal_dp(value, precision).with_context(|| {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the raw provider payload for the field: a 0 here usually means the value was missing or defaulted, not genuinely zero.
  2. Guard upstream: skip zero-size rows before reconciliation instead of failing the whole batch.
  3. Verify parsing (string-to-Decimal) is not silently yielding 0 for empty or malformed values.
  4. If zero is legitimately possible for this field, call validate_quantity_evidence with allow_zero=true.

Example fix

// before
validate_quantity_evidence(trade.size, precision, "size", false)?;
// after
if trade.size.is_zero() {
    return Ok(()); // skip empty rows emitted by provider
}
validate_quantity_evidence(trade.size, precision, "size", false)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_positive(v: Decimal) -> bool { v > Decimal::ZERO }

Try / catch

match validate_quantity_evidence(size, precision, "size", false) {
    Err(e) if e.to_string().contains("must be positive") => { skip_trade(trade.id); Ok(()) }
    other => other,
}

Prevention

When it happens

Trigger: validate_order_row_values or validate_trade_values calls validate_quantity_evidence with allow_zero=false and the Decimal value is 0 or negative — e.g. a trade row with size 0, or an order row where the filled quantity is zero.

Common situations: Provider emitting placeholder rows with zero sizes (dust, cancelled-before-fill); a partially parsed field defaulting to 0 because the real value was missing; division/rounding upstream producing 0.

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


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