nautechsystems/nautilus_trader · error

PolymarketFeeModel requires a taker-only fee schedule

Error message

PolymarketFeeModel requires a taker-only fee schedule

What it means

PolymarketFeeModel only supports taker-only fee schedules. During commission calculation, validate_schedule rejects any schedule where taker_only is false, because Polymarket fee logic cannot model maker rebates correctly. This is a fail-fast invariant to prevent silently wrong commission math.

Source

Thrown at crates/adapters/polymarket/src/models.rs:126

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},
        instruments::{Instrument, InstrumentAny, stubs::audusd_sim},
        orders::{OrderAny, builder::OrderTestBuilder, stubs::TestOrderStubs},
        types::{Price, Quantity},
    };
    use rstest::rstest;
    use rust_decimal::Decimal;
    use rust_decimal_macros::dec;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set taker_only=true on the FeeModel schedule before passing it to PolymarketFeeModel
  2. Remove any maker/rebate fields and construct the schedule via the Polymarket-specific constructor that defaults to taker_only
  3. If maker fees are genuinely needed, use a different fee model — PolymarketFeeModel intentionally does not support them

Example fix

// before
let schedule = FeeModel::new(rebate_rate, false /* taker_only */);
PolymarketFeeModel::new(schedule)?;
// after
let schedule = FeeModel::new(Decimal::ZERO, true /* taker_only */);
PolymarketFeeModel::new(schedule)?;
Defensive patterns

Strategy: validation

Validate before calling

if !schedule.taker_only {
    return Err(anyhow!("schedule must be taker_only for Polymarket"));
}
let fee_model = PolymarketFeeModel::new(schedule)?;

Type guard

fn is_taker_only(s: &FeeModel) -> bool { s.taker_only }

Prevention

When it happens

Trigger: Constructing a PolymarketFeeModel (or calling get_commission) with a FeeModel whose taker_only flag is false, e.g. reusing a schedule copied from another venue that includes maker/rebate tiers.

Common situations: Reusing a generic fee schedule across adapters; building a schedule from config where a maker rebate rate was set; copying a CEX fee schedule that supports maker rebates.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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