{"record":{"id":"c47b2ae322e8162b","repo":"nautechsystems/nautilus_trader","slug":"field-value-must-be-non-negative","errorCode":null,"errorMessage":"{field} {value} must be non-negative","messagePattern":"(.+?) (.+?) must be non-negative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/reconciliation.rs","lineNumber":274,"sourceCode":"    let instrument_outcome = binary\n        .outcome\n        .context(\"Polymarket instrument is missing outcome metadata\")?;\n    anyhow::ensure!(\n        instrument_outcome == outcome.as_str(),\n        \"provider outcome {outcome} does not match instrument outcome {instrument_outcome}\",\n    );\n\n    Ok(())\n}\n\nfn validate_quantity_evidence(\n    value: Decimal,\n    precision: u8,\n    field: &str,\n    allow_zero: bool,\n) -> anyhow::Result<()> {\n    if allow_zero {\n        anyhow::ensure!(\n            value >= Decimal::ZERO,\n            \"{field} {value} must be non-negative\"\n        );\n    } else {\n        anyhow::ensure!(value > Decimal::ZERO, \"{field} {value} must be positive\");\n    }\n\n    let quantity = Quantity::from_decimal_dp(value, precision).with_context(|| {\n        format!(\"failed to represent {field} {value} with quantity precision {precision}\")\n    })?;\n    anyhow::ensure!(\n        quantity.as_decimal() == value,\n        \"{field} {value} is not exactly representable with quantity precision {precision}\",\n    );\n    Ok(())\n}\n\nfn validate_price_evidence(value: Decimal, precision: u8, field: &str) -> anyhow::Result<()> {","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/reconciliation.rs#L256-L292","documentation":"validate_quantity_evidence enforces that a quantity-like decimal from provider evidence is usable as a domain Quantity. When allow_zero is set, the value must be >= 0; this error fires for a negative value where zero is permitted (e.g. a cumulative/cancelled quantity).","triggerScenarios":"validate_order_row_values or validate_trade_values passes a negative Decimal for a field validated with allow_zero=true (e.g. negative size, negative filled quantity from the provider).","commonSituations":"Provider API returning signed amounts for cancellations or decreases; subtracting values upstream and passing a delta instead of an absolute quantity; sign-convention changes in provider payloads.","solutions":["Log the raw provider field and check whether the endpoint returns signed deltas; convert to absolute values before validation.","Verify upstream arithmetic is not accidentally negating the value (e.g. size_remaining = size - filled with bad inputs).","Skip or clamp obviously invalid negative rows only after confirming they represent no-op events.","Report/provider-side: check for API version changes that introduced signed semantics."],"exampleFix":"// before\nvalidate_quantity_evidence(row.size, precision, \"size\", true)?;\n// after\nlet size = row.size;\nanyhow::ensure!(size >= Decimal::ZERO, \"provider size must be non-negative, got {size}\");\nvalidate_quantity_evidence(size, precision, \"size\", true)?;","handlingStrategy":"validation","validationCode":"fn is_non_negative(v: Decimal) -> bool { v >= Decimal::ZERO }","typeGuard":null,"tryCatchPattern":"match validate_quantity_evidence(value, precision, field, true) {\n    Ok(()) => (),\n    Err(e) if e.to_string().contains(\"non-negative\") => warn!(\"skipping negative {} for {}\", field, trade_id),\n    Err(e) => return Err(e),\n}","preventionTips":["Convert signed provider deltas to absolute values before quantity validation","Check sign conventions of any endpoint returning cancellation/decrease amounts","Assert quantities are non-negative at parse time, not deep in reconciliation"],"tags":["rust","validation","decimal","quantity"],"backgroundTag":"value-out-of-range","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"}