nautechsystems/nautilus_trader · error
Polymarket fee rate must be greater than or equal to zero
Error message
Polymarket fee rate must be greater than or equal to zero
What it means
validate_schedule rejects fee schedules with a negative rate, since a fee rate below zero is meaningless for this model (it would turn commission into a payout). The rate comes from the market's fee schedule in the binary option's instrument info.
Source
Thrown at crates/adapters/polymarket/src/models.rs:118
.round_dp(5),
LiquiditySide::Taker => fee_equivalent.round_dp(5),
LiquiditySide::NoLiquiditySide => unreachable!(),
};
Money::from_decimal(commission, instrument.quote_currency()).map_err(Into::into)
}
}
fn validate_schedule(schedule: &FeeSchedule) -> anyhow::Result<()> {
if schedule.exponent != Decimal::ONE {
anyhow::bail!(
"PolymarketFeeModel requires fee schedule exponent 1, was {}",
schedule.exponent
);
}
if schedule.rate < Decimal::ZERO {
anyhow::bail!("Polymarket fee rate must be greater than or equal to zero");
}
if !(Decimal::ZERO..=Decimal::ONE).contains(&schedule.rebate_rate) {
anyhow::bail!("Polymarket rebate rate must be in [0, 1]");
}
if !schedule.taker_only {
anyhow::bail!("PolymarketFeeModel requires a taker-only fee schedule");
}
Ok(())
}
#[cfg(test)]
mod tests {
use nautilus_core::UnixNanos;
use nautilus_execution::models::fee::{FeeModel, FeeModelHandle};
use nautilus_model::{
enums::{LiquiditySide, OrderSide, OrderType},View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the fee schedule source (instrument info) and correct the negative rate value.
- Validate fee schedule data at instrument-build time so bad schedules are rejected earlier.
- Check whether the API response was misparsed (e.g. a rebate misread as a rate).
- Fix test fixtures to use non-negative rates.
Example fix
// before
let schedule = FeeSchedule { rate: Decimal::new(-5, 3), .. };
// after
let schedule = FeeSchedule { rate: Decimal::new(5, 3), .. }; // 0.005 Defensive patterns
Strategy: validation
Validate before calling
if schedule.rate < Decimal::ZERO {
return Err("negative fee rate in schedule".into());
} Type guard
fn has_valid_rate(s: &FeeSchedule) -> bool {
s.rate >= Decimal::ZERO
} Try / catch
match fee_model.get_commission(&order, qty, px, &instrument) {
Ok(fee) => fee,
Err(e) if e.to_string().contains("greater than or equal to zero") => {
log::error!("corrupt fee schedule (negative rate); refusing to trade");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Validate fee schedules when building instruments, not at trade time.
- Verify API-to-Decimal parsing preserves signs and scales.
- Review hand-written fixtures for plausible values.
When it happens
Trigger: get_commission encounters a FeeSchedule whose rate < 0 — from a malformed CLOB API response, bad manual fixture, or sign error when constructing the schedule.
Common situations: Hand-written test fixtures with negative rates; API/schema changes altering how the rate is encoded; data pipelines mangling the sign.
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
- PolymarketFeeModel requires a fill price in [0, 1]
- PolymarketFeeModel requires fee schedule exponent 1, was {}
- Polymarket rebate rate must be in [0, 1]
- builder fee rate must be non-negative
- fee quantity must be non-negative
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/fd5508bed899a1e0.
Report an issue: GitHub.