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
- Check the raw provider payload for the field: a 0 here usually means the value was missing or defaulted, not genuinely zero.
- Guard upstream: skip zero-size rows before reconciliation instead of failing the whole batch.
- Verify parsing (string-to-Decimal) is not silently yielding 0 for empty or malformed values.
- 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
- Skip zero-size provider rows before reconciliation
- Check that Decimal parsing of empty/missing fields fails loudly instead of yielding 0
- Review upstream arithmetic that can produce 0 via subtraction or rounding
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
- {field} {value} must be non-negative
- AX requires whole contract quantities, was {}
- Order quantity must be at least 1 contract
- AX minimum_order_size must be a positive whole number, was {
- AX initial_margin_pct must be positive, was {initial_margin_
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/775c533fbb63fc6d.
Report an issue: GitHub.