nautechsystems/nautilus_trader · error

fee rate must be non-negative

Error message

fee rate must be non-negative

What it means

The Polymarket adapter's fee_curve_rate validates that the configured maker/taker fee rate is non-negative before computing a curve-based fee. A negative fee rate would produce nonsensical negative commissions, so the adapter rejects it early with anyhow::ensure!. This is an input-validation guard on fee parameters parsed from venue config or fee data.

Source

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

) -> 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!(
        fee_exponent >= Decimal::ZERO,
        "fee exponent must be non-negative"
    );
    anyhow::ensure!(
        (Decimal::ZERO..=Decimal::ONE).contains(&price),
        "fee price must be in [0, 1]"
    );

    if fee_rate.is_zero() {
        return Ok(Decimal::ZERO);
    }
    let base = price * (Decimal::ONE - price);
    let base_f64: f64 = base
        .try_into()
        .context("fee curve base is not representable")?;
    let exponent_f64: f64 = fee_exponent
        .try_into()

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the fee-rate config value passed to compute_commission/adjust_market_buy_amount and remove the leading minus sign.
  2. Clamp or validate fee_rate >= 0 at config-load time so invalid values fail at startup, not mid-order.
  3. If the fee comes from a parsed venue payload, verify the parser applies the venue's sign convention correctly.

Example fix

// before
let fee_rate = Decimal::from_str("-0.001")?;
let fee = compute_commission(fee_rate, price, fee_exponent)?;
// after
let fee_rate = Decimal::from_str("0.001")?;
assert!(fee_rate >= Decimal::ZERO);
let fee = compute_commission(fee_rate, price, fee_exponent)?;
Defensive patterns

Strategy: validation

Validate before calling

if fee_rate < Decimal::ZERO { return Err(anyhow!("fee rate must be non-negative: {fee_rate}")); }

Type guard

fn is_valid_fee_rate(rate: Decimal) -> bool { rate >= Decimal::ZERO }

Prevention

When it happens

Trigger: Calling adjust_market_buy_amount or compute_commission (which call fee_curve_rate) with a fee_rate < 0 — e.g. a config value of '-0.001' for a maker fee rate, or a sign-flipped fee parsed from venue data.

Common situations: Misconfiguration in fee settings where fees are entered as negative 'discounts'; parsing fee rates from venue responses with inconsistent sign conventions.

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/f44343123023c8ec. Report an issue: GitHub.