{"record":{"id":"11b8766d2d25dd49","repo":"nautechsystems/nautilus_trader","slug":"quantity-field-quantity-must-be-positive","errorCode":null,"errorMessage":"{quantity_field} {quantity} must be positive","messagePattern":"(.+?) (.+?) must be positive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/reconciliation.rs","lineNumber":418,"sourceCode":"\nfn validate_trade_values(\n    quantity: Decimal,\n    price: Decimal,\n    size_precision: u8,\n    quantity_field: &str,\n    price_field: &str,\n) -> anyhow::Result<Price> {\n    validate_quantity_evidence(quantity, size_precision, quantity_field, false)?;\n    validate_historical_price_evidence(price, price_field)\n}\n\nfn validate_pending_trade_values(\n    quantity: Decimal,\n    price: Decimal,\n    quantity_field: &str,\n    price_field: &str,\n) -> anyhow::Result<()> {\n    anyhow::ensure!(\n        quantity > Decimal::ZERO,\n        \"{quantity_field} {quantity} must be positive\"\n    );\n    anyhow::ensure!(\n        price > Decimal::ZERO && price < Decimal::ONE,\n        \"{price_field} {price} must be greater than zero and less than one\",\n    );\n    Ok(())\n}\n\nfn require_trade_timestamp(\n    ts_event: Option<UnixNanos>,\n    trade: &PolymarketTradeReport,\n) -> anyhow::Result<UnixNanos> {\n    ts_event.with_context(|| {\n        format!(\n            \"selected trade {} has invalid match_time {}\",\n            trade.id, trade.match_time,","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/reconciliation.rs#L400-L436","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Skip orders whose remaining quantity is zero before calling classify_target_trade.","Clamp or early-return when quantity <= 0 with a debug log instead of feeding it into reconciliation.","Fix the upstream computation that yields a negative remaining quantity (typically size - filled with inconsistent units)."],"exampleFix":"// before\nlet remaining = total_size - filled; // can be 0 or negative\nvalidate_pending_trade_values(remaining, price, \"remaining_size\", \"price\")?;\n// after\nlet remaining = (total_size - filled).max(Decimal::ZERO);\nif remaining.is_zero() { return Ok(None); } // skip fully-filled orders\nvalidate_pending_trade_values(remaining, price, \"remaining_size\", \"price\")?;","handlingStrategy":"validation","validationCode":"fn is_positive(q: rust_decimal::Decimal) -> bool { q > rust_decimal::Decimal::ZERO }\nif !is_positive(remaining) { return Ok(None); } // skip fully-filled/closed trades","typeGuard":"fn is_valid_pending_qty(q: &rust_decimal::Decimal) -> bool { q.is_sign_positive() && !q.is_zero() }","tryCatchPattern":"match classify_target_trade(&order, &evidence) {\n    Err(e) if e.to_string().ends_with(\"must be positive\") => Ok(None), // treat as nothing pending\n    other => other,\n}","preventionTips":["Filter out fully-filled orders (remaining == 0) before reconciliation","Use saturating/checked subtraction for remaining-size math to avoid negative quantities","Sanity-check provider size fields for 0 values on closed markets"],"tags":["polymarket","reconciliation","quantity-validation","decimal"],"backgroundTag":"invalid-argument-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}