nautechsystems/nautilus_trader · error

fee quantity must be non-negative

Error message

fee quantity must be non-negative

What it means

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".

Source

Thrown at crates/adapters/polymarket/src/execution/parse.rs:594

/// the post-trade rate that actually applied; under V2 the fee is no longer carried
/// in the signed order, so we compute commissions from the instrument's fee schedule
/// rather than reading any cap off the order body.
///
/// # Errors
///
/// Returns an error for negative rates, exponents, or sizes, prices outside `[0, 1]`,
/// or a calculation that cannot be represented.
///
/// # References
/// <https://docs.polymarket.com/trading/fees>
pub fn compute_commission(
    fee_rate: Decimal,
    fee_exponent: Decimal,
    size: Decimal,
    price: Decimal,
    liquidity_side: LiquiditySide,
) -> anyhow::Result<Decimal> {
    anyhow::ensure!(size >= Decimal::ZERO, "fee quantity must be non-negative");
    let rate = fee_curve_rate(fee_rate, price, fee_exponent)?;

    if liquidity_side != LiquiditySide::Taker {
        return Ok(Decimal::ZERO);
    }
    let commission = size
        .checked_mul(rate)
        .context("commission calculation overflow")?;
    Ok(commission.round_dp(5))
}

fn fee_curve_rate(
    fee_rate: Decimal,
    price: Decimal,
    fee_exponent: Decimal,
) -> anyhow::Result<Decimal> {
    anyhow::ensure!(fee_rate >= Decimal::ZERO, "fee rate must be non-negative");
    anyhow::ensure!(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Sanitize the fill size before computing commission (take the absolute value or reject negative-size reports at parse time).
  2. Fix the upstream fill parsing/netting code that produced a negative quantity.
  3. If the negative value indicates an invalid venue payload, drop the fill report and log the anomaly instead of computing a fee.

Example fix

// before
let commission = compute_commission(fee_rate, exponent, size /* -5 */, price, side)?;
// after
anyhow::ensure!(size >= Decimal::ZERO, "invalid fill size {size}");
let commission = compute_commission(fee_rate, exponent, size, price, side)?;
Defensive patterns

Strategy: validation

Validate before calling

let size = size.abs();
if size < Decimal::ZERO { return Err("negative fill size in report".into()); }

Type guard

fn is_valid_fill_size(size: Decimal) -> bool { size >= Decimal::ZERO }

Try / catch

let commission = match compute_commission(rate, exponent, size, price, side) {
    Ok(c) => c,
    Err(e) if e.to_string().contains("non-negative") => {
        tracing::warn!("dropping malformed fill with negative size");
        Decimal::ZERO
    }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: 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.

Common situations: Venue fill payloads parsed without abs()/sign normalization; maker/taker netting logic subtracting quantities into the negative; corrupted or hand-crafted fill report fixtures.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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