{"record":{"id":"c49cdc9ac5b54d19","repo":"nautechsystems/nautilus_trader","slug":"fee-quantity-must-be-non-negative","errorCode":null,"errorMessage":"fee quantity must be non-negative","messagePattern":"fee quantity must be non-negative","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/parse.rs","lineNumber":594,"sourceCode":"/// the post-trade rate that actually applied; under V2 the fee is no longer carried\n/// in the signed order, so we compute commissions from the instrument's fee schedule\n/// rather than reading any cap off the order body.\n///\n/// # Errors\n///\n/// Returns an error for negative rates, exponents, or sizes, prices outside `[0, 1]`,\n/// or a calculation that cannot be represented.\n///\n/// # References\n/// <https://docs.polymarket.com/trading/fees>\npub fn compute_commission(\n    fee_rate: Decimal,\n    fee_exponent: Decimal,\n    size: Decimal,\n    price: Decimal,\n    liquidity_side: LiquiditySide,\n) -> anyhow::Result<Decimal> {\n    anyhow::ensure!(size >= Decimal::ZERO, \"fee quantity must be non-negative\");\n    let rate = fee_curve_rate(fee_rate, price, fee_exponent)?;\n\n    if liquidity_side != LiquiditySide::Taker {\n        return Ok(Decimal::ZERO);\n    }\n    let commission = size\n        .checked_mul(rate)\n        .context(\"commission calculation overflow\")?;\n    Ok(commission.round_dp(5))\n}\n\nfn fee_curve_rate(\n    fee_rate: Decimal,\n    price: Decimal,\n    fee_exponent: Decimal,\n) -> anyhow::Result<Decimal> {\n    anyhow::ensure!(fee_rate >= Decimal::ZERO, \"fee rate must be non-negative\");\n    anyhow::ensure!(","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/parse.rs#L576-L612","documentation":"compute_commission calculates the venue commission for a fill and requires the fill size (quantity) to be non-negative. A negative size would invert fee math, so the function rejects it up front with \"fee quantity must be non-negative\".","triggerScenarios":"Calling compute_commission (directly or via calculate_commission, parse_validated_fill_report, parse_validated_maker_fill_report) with size < 0 — e.g. a fill report carrying a signed negative quantity or a sign error when netting fills.","commonSituations":"Venue fill payloads parsed without abs()/sign normalization; maker/taker netting logic subtracting quantities into the negative; corrupted or hand-crafted fill report fixtures.","solutions":["Sanitize the fill size before computing commission (take the absolute value or reject negative-size reports at parse time).","Fix the upstream fill parsing/netting code that produced a negative quantity.","If the negative value indicates an invalid venue payload, drop the fill report and log the anomaly instead of computing a fee."],"exampleFix":"// before\nlet commission = compute_commission(fee_rate, exponent, size /* -5 */, price, side)?;\n// after\nanyhow::ensure!(size >= Decimal::ZERO, \"invalid fill size {size}\");\nlet commission = compute_commission(fee_rate, exponent, size, price, side)?;","handlingStrategy":"validation","validationCode":"let size = size.abs();\nif size < Decimal::ZERO { return Err(\"negative fill size in report\".into()); }","typeGuard":"fn is_valid_fill_size(size: Decimal) -> bool { size >= Decimal::ZERO }","tryCatchPattern":"let commission = match compute_commission(rate, exponent, size, price, side) {\n    Ok(c) => c,\n    Err(e) if e.to_string().contains(\"non-negative\") => {\n        tracing::warn!(\"dropping malformed fill with negative size\");\n        Decimal::ZERO\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Normalize fill quantities (abs / sign checks) when parsing venue fill reports.","Validate fill reports against a schema before fee computation.","Flag negative sizes as data-quality anomalies for upstream investigation."],"tags":["polymarket","commission","fees","validation"],"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-14T00:17:10.932Z"}